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

[ImportParserPlugin] fix return value when creating context for import() #8294

Merged

Conversation

ljqx
Copy link
Member

@ljqx ljqx commented Oct 28, 2018

This PR fixes #8293 . Now ImportParserPlugin returns true when creating context, which stops parser walking on param of import(), then DefinePlugin fails to change value of it.

What kind of change does this PR introduce?
a bugfix

Did you add tests for your changes?
yes

Does this PR introduce a breaking change?
no

What needs to be documented once your changes are merged?
nothing

@webpack-bot
Copy link
Contributor

For maintainers only:

  • This need to be documented (issue in webpack/webpack.js.org will be filed when merged)

@ljqx ljqx changed the title import parser plugin fix context return [ImportParserPlugin] fix return value when creating context for import() Oct 28, 2018
@@ -254,7 +254,7 @@ class ImportParserPlugin {
dep.loc = expr.loc;
dep.optional = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
return false;
Copy link
Member

Choose a reason for hiding this comment

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

I think walking the full expression is not correct as it would handle constant pieces twice.

like this one: import(`./${CONSTANT}/${DEFINED_EXPRESSION}`)

with DefinePlugin({ CONSTANT: JSON.stringify("folder"), DEFINED_EXPRESSION: "foobar" })

Could you add this to the test?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sadly you are right. Seems only reliable way to fix this is to walk necessary expressions in ContextDependencyHelpers. I'll push a new iteration

@webpack-bot
Copy link
Contributor

@ljqx Thanks for your update.

I labeled the Pull Request so reviewers will review it again.

@sokra Please review the new changes.

if (param.isConditional()) {
param.options.forEach(param => {
const result = this.processItem(parser, expr, param);
param.options.forEach((param, idx) => {
Copy link
Member

Choose a reason for hiding this comment

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

We need some tests for this.

I think this fails if multiple ?: operators are nested. In this case options has more than 2 elements:

import(a ?
  (b ? "x" : `./${CONST_PREFIX}/${DEFINED_EXPRESSION}/${CONST_SUFFIX}`) :
  (c ? `./${CONST_PREFIX}/${DEFINED_EXPRESSION}/${CONST_SUFFIX}` : "y")
)

I think it make sense to add the expression tracking to the BasicEvaluatedExpression (i. e. setExpression for the whole thing, and setTemplateString(quasis, parts) for template strings), instead of reimplementing it here.

  • You can call setExpression in Parser.evaluateExpression to do it once for all
  • You need to change getSimplifiedTemplateResult in Parser a bit to get all the expressions too.
  • BasicEvaluatedExpression.setTemplateString now takes quasis which is still the same, parts which are all the quasis and epxressions as BasicEvaluatedExpressions, so all the parts of the template string.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks! I've thought it's too heavy for this PR, but surely it's more appropriate for easily tracking back the expr from BasicEvaluatedExpression

@@ -45,7 +45,9 @@ ContextDependencyHelpers.create = (
Dep,
range,
param,
paramExpr,
Copy link
Member

Choose a reason for hiding this comment

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

You no longer need this argument, as param now contains this information.

@@ -84,7 +86,17 @@ ContextDependencyHelpers.create = (
);
dep.loc = expr.loc;
const replaces = [];
if (prefixRange && prefix !== prefixRaw) {
const templateLiteral =
Copy link
Member

Choose a reason for hiding this comment

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

You can walk all parts of the param.

  • If it's a constant string: replace the range with the string (push to replaces)
  • If it's not constant: walk it with the parser

@@ -21,20 +21,24 @@ class RequireResolveDependencyParserPlugin {
if (expr.arguments.length !== 1) return;
const param = parser.evaluateExpression(expr.arguments[0]);
if (param.isConditional()) {
for (const option of param.options) {
param.options.forEach((option, idx) => {
Copy link
Member

Choose a reason for hiding this comment

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

All these changes can be reverted as the expression is now tracked in the BasicEvaluatedExpression.

expr,
parser,
Copy link
Member

Choose a reason for hiding this comment

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

To avoid a breaking change, make this argument optional. In this case expressions are not walked.

Copy link
Member Author

Choose a reason for hiding this comment

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

OK, thanks! Then in this PR I'll only handle import() case, then later working on AMD define, require, CommonJS require and require.resolve

parser.walkExpression(e);
}
});
if (prefix !== prefixRaw) {
replaces.push({
range: prefixRange,
value: prefix
Copy link
Member

Choose a reason for hiding this comment

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

Lower in this file, at the else case, you need to walk the whole expression.

@ljqx
Copy link
Member Author

ljqx commented Oct 30, 2018

@sokra , I've published a new iteration. It's more readable now. Thanks!

@webpack-bot
Copy link
Contributor

Thank you for your pull request! The most important CI builds succeeded, we’ll review the pull request soon.

fix bug which keeps const conditional expression in bundle
remove parsing code from ContextDependencyHelpers
@webpack-bot
Copy link
Contributor

It looks like this Pull Request doesn't include enough test cases (based on Code Coverage analysis of the PR diff).

A PR need to be covered by tests if you add a new feature (we want to make sure that your feature is working) or if you fix a bug (we want to make sure that we don't run into a regression in future).

@ljqx Please check if this is appliable to your PR and if you can add more test cases.

Read the test readme for details how to write test cases.

@sokra sokra merged commit eb68316 into webpack:master Nov 3, 2018
@sokra
Copy link
Member

sokra commented Nov 3, 2018

Thanks

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

Successfully merging this pull request may close these issues.

DefinePlugin regression
3 participants