Description
Version
4.5.11
Environment info
Environment Info:
System:
OS: Linux 5.8 Ubuntu 20.04.2 LTS (Focal Fossa)
CPU: (8) x64 Intel(R) Core(TM) i5-8365U CPU @ 1.60GHz
Binaries:
Node: 15.6.0 - ~/.nvm/versions/node/v15.6.0/bin/node
Yarn: Not Found
npm: 6.14.11 - ~/.nvm/versions/node/v15.6.0/bin/npm
Browsers:
Chrome: 88.0.4324.150
Firefox: 85.0.1
npmGlobalPackages:
@vue/cli: 4.5.11
Steps to reproduce
Create a plugin with the following generator, and invoke it multiple times.
module.exports = function (api) {
api.injectImports(api.entryFile, `import './${Date.now()}.js'`);
}
What is expected?
Every time the plugin is invoked, it will add a new import, as the filename of the import is unique.
What is actually happening?
The first time the plugin is invoked, the import is added. Subsequent runs of the plugin won't add new imports.
The culprit seems to be the toImportHash
function in @vue/cli/lib/util/codemods/injectImports.js.
jscodeshift outputs nodes according to the ESTree spec. According to this spec, for an ImportDeclaration the source is of type Literal. Literal
doesn't have a raw
property.
This is where different parsers output different results, as can be seen in this AST Explorer example. Parsers like Acorn and Flow do have the raw
propery. However, jscodeshift uses @babel/parser
by default, which doesn't have this property.
That is why toImportHash
fails for this case. node.source.raw
will never be defined, so it won't be included in the result of JSON.stringify
. Additionally, node.specifiers
will be always be an empty array.
That means that toImportAST
for something like import './side-effects-only.js'
will always return '{"specifiers":[]}'
, additional side-effects-only imports will be marked as duplicates, and won't be added.
For a regular import like import Vue from 'vue'
, toImportAST
will return '{"specifiers":["Vue"]}'
which is unique enough for basically every case, and why the problem doesn't occur for those.
Suggested solution
Instead of using node.source.raw
, node.source.value
is probably the safer option, as that is defined in the spec so won't be dependent on the parser. That means that the type of quotes used in the string will get lost, but I expect that to be acceptable.