-
Notifications
You must be signed in to change notification settings - Fork 400
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
feat(rollup-plugin): warn stylesheet import for CSS extensibility #3270
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the simplicity of this implementation. It's more elegant IMO than the ?optional=true
approach. However I am concerned about the potentially breaking change, so I would advise the following:
- Rather than introduce a breaking change, let's keep the existing functionality
- but let's log a warning for the case you identify, where a non-implicitly-imported CSS file doesn't exist (and potentially report that warning somewhere)
Otherwise I'm afraid we will run into breakages in practice. An example of this would be:
- Customer writes
import stylesheet from './stylesheet.css'
- Deletes
stylesheet.css
later, forgets to remove theimport
- Everything works
- Boom, it breaks after this PR
const { scoped, filename } = parseQueryParamsForScopedOption(absPath); | ||
if (scoped) { | ||
absPath = filename; // remove query param | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose we could remove the if
and just always set absPath = filename
. If scoped
is false, then the two strings should be equal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's correct. I've removed it.
throw generateCompilerError(ModuleResolutionErrors.NONEXISTENT_FILE, { | ||
messageArgs: [filename], | ||
origin: { filename }, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One nice thing about this PR is that we are no longer actually reading from the filesystem – we are just doing path
string comparisons.
Also we don't have to generate our own compiler error here – I assume because Rollup will do it for us?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great advice, I've switched to use this.warn()
instead.
BTW it looks like there is already a |
@@ -161,4 +161,21 @@ describe('resolver', () => { | |||
|
|||
expect(warnings).toHaveLength(0); | |||
}); | |||
|
|||
it('should throw an error when import stylesheet file is missing', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it('should throw an error when import stylesheet file is missing', async () => { | |
it('should emit a warning when import stylesheet file is missing', async () => { |
expect(warnings).toHaveLength(1); | ||
expect(warnings[0].message).toMatch( | ||
/The imported CSS file .+\/stylesheet.css does not exist: Importing it as undefined./ | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we check that the code is still compiled successfully here?
return fs.readFileSync(id, 'utf8'); | ||
} else { | ||
this.warn( | ||
`The imported CSS file ${id} does not exist: Importing it as undefined.` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
`The imported CSS file ${id} does not exist: Importing it as undefined.` | |
`The imported CSS file ${id} does not exist: Importing it as undefined. ` + | |
`This behavior may be removed in a future version of LWC. Please avoid importing a ` + | |
`CSS file that does not exist.` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Some minor nitpicks.
Details
This PR updates
rollup-plugin
on stylesheet imports so that if a component imports an non-existing CSS file it willthrow an errorlog a warning message, while keep the current behavior treating any non-existing CSS file as empty string (compiled toexport default undefined
).The previous behavior can be problematic because the new CSS extensibility feature (a.k.a. programmatic style injection) allows users to override a component's style by programmatically importing a stylesheet module from JavaScript using an import statement.
We should enforce that the imported CSS file must exist and if not the compilation should fail instead of treating it as an empty string so that developers can be informed the issue during build time.We should warn developers that the imported CSS file does not exist.More details can be found in the LWC stylesheets modules section of the RFC.
The RFC proposes to use a new query parameter
optional=true
to indicate that an imported CSS is optional as following example.This can be achieved by changing the template compiler to include the new
optional
query param in the implicit stylesheet imports. However, during implementation I find that it might be tricky for the case where component JS file also imports the same implicit stylesheet as following.Note that this component
app
also imports its implicit CSSapp.css
and its compiled HTML file will haveimport _implicitStylesheets from "./app.css?optional=true";
thus the rollup plugin needs to handle bothapp.css
andapp.css?optional=true
properly to make sure it is the exact same file. And it can be confusing as in HTML it is marked as optional but in JS its marked as required. This case can be special handled but it could be slightly more complicated and could cause confusion in the future.Instead I propose to simply check if a CSS import if implicit similar to how lwc-plaform does the check. Although this can be less explicit, this approach has some benefits:
scoped
.Does this pull request introduce a breaking change?
Does this pull request introduce an observable change?
This would be an observable change if existing components are importing a non-existing CSS module. But I think this should be a rare case and if it happens it is more likely an unnoticed error by component author and should be fixed by removing the import of non-existing CSS module.GUS work item
W-10183295