Skip to content

fix resolve bindings issue#1919

Open
xtan-atlas wants to merge 6 commits into
masterfrom
fix-babel-plugin-resolve-issue
Open

fix resolve bindings issue#1919
xtan-atlas wants to merge 6 commits into
masterfrom
fix-babel-plugin-resolve-issue

Conversation

@xtan-atlas

@xtan-atlas xtan-atlas commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

What is this change?

This updates @compiled/babel-plugin binding resolution so imported bindings are resolved from the file being transformed rather than from the Compiled plugin package.

It also adds support for simple package exports resolution when using the resolve package:

  • root package imports: import '@pkg'exports['.']
  • package subpath imports: import '@pkg/foo'exports['./foo']

A regression test was added for xcss usage that references values imported from another package via both root and subpath exports.

Verified in AFM Spike PR with yarn patch: https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/413960 (build is green)

Why are we making this change?

Compiled performs binding resolution while statically evaluating styles used in paths like xcss / cssMap.

Some valid source code includes imported values inside style expressions or xcss expressions, for example:

import { media } from '@atlaskit/primitives/responsive';
import { fg } from '@atlaskit/feature-gate-js-client/feature-gates';
import { someConstant } from '@some/package';

xcss({
  [media.above.sm]: {
    flexWrap: 'nowrap',
  },
});

xcss={cx(
  styles.base,
  fg('some-feature') && styles.enabled,
)}

Before this change, package imports encountered during binding resolution were resolved without a basedir. That meant the resolve package tried to resolve them from the Compiled plugin package location, for example:

node_modules/@compiled/babel-plugin/dist/utils
instead of from the source file being transformed.
This caused false MODULE_NOT_FOUND errors for otherwise valid imports, such as:

Cannot find module '@atlaskit/feature-gate-js-client'
from '.../node_modules/@compiled/babel-plugin/dist/utils'
or:

Cannot find module '@atlaskit/feature-gate-js-client/feature-gates'
from '.../node_modules/@compiled/babel-plugin/dist/utils'
This is broader than responsive media usage. It can happen for feature gates, constants, helpers, or any imported package value that Compiled encounters during binding analysis.

How are we making this change?

(Optional.)


PR checklist

Don't delete me!

I have...

  • Updated or added applicable tests
  • Added a changeset (if making any changes that affect Compiled's behaviour)

@changeset-bot

changeset-bot Bot commented Jul 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 0ea1044

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@compiled/babel-plugin Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify

netlify Bot commented Jul 14, 2026

Copy link
Copy Markdown

Deploy Preview for compiled-css-in-js canceled.

Name Link
🔨 Latest commit 0ea1044
🔍 Latest deploy log https://app.netlify.com/projects/compiled-css-in-js/deploys/6a5858e21c92600008c61477

gridTemplateColumns: '1fr 1fr',
flexWrap: 'wrap',
flexDirection: 'column',
[akMedia.above.sm]: {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see, it's about this…yeah, media needs to be fixed/removed/something'd.

@atlaskit/css with bounded interface is the way to solve it, but we do not have a solution as Compiled decided to drop the work to make global cached tokens/constants a thing.

Comment on lines +302 to +308
try {
modulePath = resolveRequest(moduleImportSource, extensions, meta);
} catch {
// Treat unresolved userland imports as dynamic values when they are unavailable
// from the Compiled plugin's module resolution context.
return;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will say, this is one of those things I liked throwing errors before, but it didn't do this consistently whatsoever…

`,
{ filename: 'checkbox-list.jsx' }
);
}).not.toThrow();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of assert not toThrow, can you have a snapshot assertion? It will be good to see what this gets transformed to.

let modulePath: string;

try {
modulePath = resolveRequest(moduleImportSource, extensions, meta);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some concerns about this approach.

When a "cannot find module X" error occurs, it most likely means the compiled resolver is not configured properly. We should fix the resolver configuration instead.

I understand that configuring a resolver to cover many use cases can be difficult. We actually came across a similar issue with media.something.something before. Could we resolve it by inlining the value? For example:

@media (min-width: 600px) {
    flexWrap: 'nowrap',
}

@kylorhall-atlassian kylorhall-atlassian Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is media.above.md has always worked in css(), but always through an error in cssMap(); I'm unclear what the difference is if this results in a compile-checked 1:1 output. Is this just a false error?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine with us codemodding away media.x.y 1:1 as well, literally deprecate, ratchet, and remove in AFM if it's a blocker and I'll redo the docs.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Kylor!
@xtan-atlas would you be able to replace media.x.y references with their corresponding inline values on a 1:1 basis, if there are not too many occurrences? I think this aligns well with our long term strategy: all variables should be localized, with no cross-file resolution at build time.

If you consider inlining the media.x.y values unsafe, I completely understand. Merging this PR as is works for me too.

@xtan-atlas xtan-atlas Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kylorhall-atlassian @liamqma I actually got it working and verified in AFM without patch by avoid inline xcss. So I can bump deps without this blocking me.

https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/413472/diff#chg-adminhub/packages/common/checkbox-list/src/ui/checkbox-list.tsx

I don't think inline is a good, we officially support media.xxx in https://atlassian.design/components/primitives/responsive/usage

But we may just need an eslint rule to cover.

@xtan-atlas xtan-atlas Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kylorhall-atlassian @liamqma , found there are more cases throwing errors, like this one:
Screenshot 2026-07-14 at 5 51 34 pm

Basically, if the inlined xcss have used variables imported, it'd break. I can't get the AFM PR green without patches or more bump from @compiled/babel-plugin... So I think it'd be better to fix properly in Compiled first.

I've updated the resolveRequest function, and tested in AFM Spike: https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/413960

I added a unit test with snapshot inline as suggested, please take a look.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OH good catch!
I see what's broken

xcss={cx(
	styles.readViewButton,
	FeatureGates.getExperimentValue('jira-aifc-ux-papercuts-sprt', 'isEnabled', false, {
		fireExperimentExposure: false,
	}) && styles.hoverStyles,
)}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this.

Another example below, which need pathFilter in resolveRequest to fix:

import { ConversationAssistantUIModes } from '@atlassian/conversation-assistant/types';

<Box
	xcss={cx(
		styles.animatedMiniModalBefore,
		mode === ConversationAssistantUIModes.MINI_MODAL && styles.animatedMiniModalAfter,
	)}
/>

@xtan-atlas
xtan-atlas marked this pull request as ready for review July 14, 2026 23:59
return resolve.sync(id, {
return resolve.sync(request, {
// Resolve imports from the file being transformed, not from this plugin's package.
basedir: dirname(filename),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from reading the description of a PR, would just this line be sufficient? why is packageFilter and pathFilter needed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tried in my spike, but didn't work unfortunately with basedir only for feature flag cases.

Screenshot 2026-07-14 at 5 51 34 pm

FeatureGates usage is like

import FeatureGates from '@atlaskit/feature-gate-js-client/feature-gates';

<Box xcss={cx(
    marginTop: 16,
    FeatureGates.getExperimentValue('xxx', 'isEnabled', false) && {
       marginTop: 0,
    })
 />

@liamqma liamqma Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, I think AFM has some atlassian-resolver that handles changes like this. The code path if (!resolver) { ... } should NOT be triggered at AFM. An error like this means the Compiled resolver is not configured properly for the situation the build runs against. It might be easier to switch the resolver at AFM rather than applying the fix here.

@kylorhall-atlassian kylorhall-atlassian Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@liamqma I would say as well, given we have the resolver config in probably 100+ places at Atlassian, it very well might be worth insourcing it—I think Atlaspack/Compiled could possibly even make it better than asking every consumer to build and maintain their own resolver logic. I do agree though, just when it's a problem in a repo that already has the resolvers configured for the past ~4 years it might need to be centralized.

@xtan-atlas xtan-atlas Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kylorhall-atlassian @liamqma I insourced @atlaskit/resolvers/compiled-resolver as a default resolver if no resolver is found from babel plugin option.

I will verify in my AFM spike

import { media as subpathMedia } from "@compiled-private/source-relative-responsive/media";
export const CheckboxList = ({ testId = "checkbox-list" }) => (
<AkBox
xcss={akXcss({

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit confused. After the transformation, should this snapshot look like

<AkBox className="..." />

?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

other existing test cases are the same, I think it's because the test util it used which made it run in runtime mode.

'@compiled/babel-plugin': patch
---

Resolve module imports relative to the transformed file when resolving bindings.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this issue specific to compiled plugin? Or does it need to be ported over atlaspack SWC plugins?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

asked AI saying not needed :)
Screenshot 2026-07-15 at 10 39 32 am

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants