Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: replace barrel exports from lwc with @lwc/ssr-runtime #5034

Merged
merged 9 commits into from
Dec 17, 2024

Conversation

jhefferman-sfdc
Copy link
Contributor

Details

Does this pull request introduce a breaking change?

  • ๐Ÿ˜ฎโ€๐Ÿ’จ No, it does not introduce a breaking change.

Does this pull request introduce an observable change?

  • ๐Ÿคž No, it does not introduce an observable change.

GUS work item

W-16984771

@jhefferman-sfdc jhefferman-sfdc requested a review from a team as a code owner December 10, 2024 22:52
@jhefferman-sfdc jhefferman-sfdc assigned wjhsf and unassigned wjhsf Dec 10, 2024
@jhefferman-sfdc jhefferman-sfdc changed the title fix: replace barrel from lwc package with '@lwc/ssr-runtime' fix: replace barrel exports from lwc with '@lwc/ssr-runtime' Dec 10, 2024
@jhefferman-sfdc jhefferman-sfdc changed the title fix: replace barrel exports from lwc with '@lwc/ssr-runtime' fix: replace barrel exports from lwc with @lwc/ssr-runtime Dec 10, 2024
unwrap,
createElement,
renderComponent,
} from 'lwc';
Copy link
Collaborator

@nolanlawson nolanlawson Dec 10, 2024

Choose a reason for hiding this comment

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

Some more tests to add:

  • export * as lwc from 'lwc'
  • export { doesNotExist } from 'lwc'
  • export { registerComponent } from 'lwc' // should be disallowed

We don't have to be perfect about this because there is already ESLint validation on LEX, but we should at least make sure that these cases work correctly.

Also a good way to confirm that the import is actually working is something like

import { LightningElement } from './barrel.js'
// ...
constructor() {
  super()
  this.isInstanceOfLightningElement = this instanceof LightningElement
}
<template>
    {isInstanceOfLightningElement}
</template>

Copy link
Contributor Author

@jhefferman-sfdc jhefferman-sfdc Dec 10, 2024

Choose a reason for hiding this comment

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

man the reviews on this team are so fast :D thank you!

export * as lwc from 'lwc'

Thanks, realized exportAllDeclaration is missing and valid, working on it now.

export { doesNotExist } from 'lwc'

Ok got you. I didn't see any coverage like that for imports, I will add some.

export { registerComponent } from 'lwc' // should be disallowed

Is this validation handled in the compiler pass or at runtime? I was confused there perhaps. 4674)

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think I got mixed up: we don't do any validation of lwc imports/exports in this repo. It's in eslint-plugin-lwc which runs on-platform already.

I thought we did some validation here, but just checked and couldn't find any.

So I think we only need to test export * as lwc then. import { doesNotExist } will likely throw an error at the Rollup level, so not worth testing.

Copy link
Contributor Author

@jhefferman-sfdc jhefferman-sfdc Dec 11, 2024

Choose a reason for hiding this comment

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

I had a similar confusion - Not sure if this is what you were thinking of but there was some sort of validation in the compiler pass and this WI dated from then (4617). But later it was moved to runtime only (4674)?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yep looks like it.

}

path.replaceWith(b.exportAllDeclaration(b.literal('@lwc/ssr-runtime')));
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't correctly handle the case of

export * as foo from 'lwc'

which is not the same as

export * from 'lwc'

In this case, we would need to maintain the foo identifier as well (try this example on https://astexplorer.net/).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you, sorry I missed this

unwrap,
createElement,
renderComponent
);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd still love for us to do something with these rather than just logging them. E.g. exposing it on the component so that the template can prove that it rendered something, and that the exports we got from here are the same ones exported from @lwc/ssr-runtime (i.e. no duplicate modules).

Also, logging here will make our tests more noisy. We already have noisy logs, but this just adds to the problem. We could do something like Promise.resolve(...) to avoid the compiler removing it.

Copy link
Contributor Author

@jhefferman-sfdc jhefferman-sfdc Dec 12, 2024

Choose a reason for hiding this comment

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

I'd still love for us to do something with these rather than just logging them. E.g. exposing it on the component so that the template can prove that it rendered something

It's a little crude, but what do you think about exposing them in the template via inner-html? Example here. The function implementations would differ between v1 and v2 ofc so I trimmed them... E.g. getComponentDef in V1 vs V2 (stub)

Also, logging here will make our tests more noisy. We already have noisy logs, but this just adds to the problem.

Ok makes sense. See above.

.replace('async function serverSideRenderComponent', 'function renderComponent')
)
.join('\n ');
}
Copy link
Collaborator

@nolanlawson nolanlawson Dec 16, 2024

Choose a reason for hiding this comment

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

I think we could make this less fragile by using a simple typeof instead of stringifying the entire function. I also tend to prefer inlining these kinds of things into fixtures instead of having shared utils (code reuse is not super important for fixture tests).

Copy link
Contributor

Choose a reason for hiding this comment

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

fn.name should also work (unless rollup mangles it)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice, that works thanks

path.replaceWith(
b.exportNamedDeclaration(
path.node.declaration,
path.node.specifiers,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's structuredClone these for safety. Ditto below for path.node.exported.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok thank you, I updated Dales replaceLwcImport impl above to keep it consistent.

Copy link
Collaborator

@nolanlawson nolanlawson left a comment

Choose a reason for hiding this comment

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

Small nits, LGTM

.replace('async function serverSideRenderComponent', 'function renderComponent')
)
.join('\n ');
}
Copy link
Contributor

Choose a reason for hiding this comment

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

fn.name should also work (unless rollup mangles it)

Comment on lines 5 to 14
imports = importsToString([
foo.getComponentDef,
foo.isComponentConstructor,
foo.createContextProvider,
foo.readonly,
foo.setFeatureFlagForTest,
foo.unwrap,
foo.createElement,
foo.renderComponent,
]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
imports = importsToString([
foo.getComponentDef,
foo.isComponentConstructor,
foo.createContextProvider,
foo.readonly,
foo.setFeatureFlagForTest,
foo.unwrap,
foo.createElement,
foo.renderComponent,
]);
imports = Object.values(foo).map(fn => fn.name);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There are a number of differences between v1/v2 but they don't impact the set of functions that are expected to work when imported so I didn't base it off the entire import. See below (v2 left, v1 right)

image

@@ -23,6 +23,12 @@ import type { CompilationMode } from '@lwc/shared';

const visitors: Visitors = {
$: { scope: true },
ExportNamedDeclaration(path) {
replaceNamedLwcExport(path);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is replaceNamedLwcExport used anywhere else? Can we just inline it here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is not, but same goes for replaceLwcImport so I was just keeping it consistent. Also feel like this file could get a little busy if we added everything inline?

@jhefferman-sfdc jhefferman-sfdc merged commit a33b390 into master Dec 17, 2024
11 checks passed
@jhefferman-sfdc jhefferman-sfdc deleted the jhefferman/handle-lwc-barrel-imports branch December 17, 2024 20:17
wjhsf added a commit that referenced this pull request Dec 20, 2024
* test(ssr): add tests for nested elements in slots (#5048)

* fix(compiler): log warning for missing name/namespace (#4825)

* test(karma): remove unnecessary IE11-related code (#5054)

* fix: replace barrel exports from `lwc` with `@lwc/ssr-runtime` (#5034)

* fix: replace barrel from `lwc` package with '@lwc/ssr-runtime'

* fix: handle * barrel case and corresponding tests

* fix: function naming

* fix: barrel import test parity

* fix: include optional exported alias for export all declaration replacement, tests

* chore: explain function name massaging in test

* fix: deep clone objects and optimize tests

* fix: remove unused shared file

* test(karma): add test for for:each issue #4889 (#5053)

* fix(ssr): missing bookends for slotted lwc:if not at the top-level (#5027)

Co-authored-by: Nolan Lawson <[email protected]>

* fix(ssr): fix HTML comment bookends for if blocks (#5055)

Co-authored-by: Will Harney <[email protected]>

* fix(ssr-compiler): namespace and name should be optional in ComponentTransformOptions (#5058)

* test(ssr): test `if` with adjacent text (#5056)

* test(karma): reduce #4889 even further (#5060)

* fix(ssr): fix `style` attribute rendering (#5061)

* fix(ssr-compiler): harmonize some wire errors (#5062)

Co-authored-by: Will Harney <[email protected]>

* fix: only call callback when needed @W-17420330 (#5064)

* fix: only call callback when needed @W-17420330

* chore: simplify test

* fix: use correct class check

* fix(ssr): render from superclass (#5063)

Co-authored-by: Nolan Lawson <[email protected]>

* test(ssr): add more superclass tests (#5065)

* fix: use correct shadow root @W-17441501 (#5070)

* fix: use correct shadow root @W-17441501

* chore: yagni i guess

* chore: ๐Ÿ›ฉ๏ธ๐Ÿ“ฆ

* If you read this, tell me so!

* fix(ssr): align csr and ssr reflective behavior (#5050)

* chore: release v8.12.2 @W-17485572 (#5075)

---------

Co-authored-by: Nolan Lawson <[email protected]>
Co-authored-by: jhefferman-sfdc <[email protected]>
Co-authored-by: Matheus Cardoso <[email protected]>
Co-authored-by: Nolan Lawson <[email protected]>
Co-authored-by: Eugene Kashida <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants