diff --git a/lib/dependencies/ImportMetaPlugin.js b/lib/dependencies/ImportMetaPlugin.js index 7d8cb8ce358..6d83842e8d2 100644 --- a/lib/dependencies/ImportMetaPlugin.js +++ b/lib/dependencies/ImportMetaPlugin.js @@ -75,6 +75,17 @@ class ImportMetaPlugin { } /// import.meta direct /// + const webpackVersion = parseInt( + require("../../package.json").version, + 10 + ); + const importMetaUrl = () => + JSON.stringify(getUrl(parser.state.module)); + const importMetaWebpackVersion = () => JSON.stringify(webpackVersion); + const importMetaUnknownProperty = members => + `${Template.toNormalComment( + "unsupported import.meta." + members.join(".") + )} undefined${propertyAccess(members, 1)}`; parser.hooks.typeof .for("import.meta") .tap( @@ -84,20 +95,48 @@ class ImportMetaPlugin { parser.hooks.expression .for("import.meta") .tap(PLUGIN_NAME, metaProperty => { - const CriticalDependencyWarning = getCriticalDependencyWarning(); - parser.state.module.addWarning( - new ModuleDependencyWarning( - parser.state.module, - new CriticalDependencyWarning( - "Accessing import.meta directly is unsupported (only property access is supported)" - ), - metaProperty.loc - ) - ); - const dep = new ConstDependency( - `${parser.isAsiPosition(metaProperty.range[0]) ? ";" : ""}({})`, - metaProperty.range - ); + const referencedPropertiesInDestructuring = + parser.destructuringAssignmentPropertiesFor(metaProperty); + if (!referencedPropertiesInDestructuring) { + const CriticalDependencyWarning = + getCriticalDependencyWarning(); + parser.state.module.addWarning( + new ModuleDependencyWarning( + parser.state.module, + new CriticalDependencyWarning( + "Accessing import.meta directly is unsupported (only property access or destructuring is supported)" + ), + metaProperty.loc + ) + ); + const dep = new ConstDependency( + `${ + parser.isAsiPosition(metaProperty.range[0]) ? ";" : "" + }({})`, + metaProperty.range + ); + dep.loc = metaProperty.loc; + parser.state.module.addPresentationalDependency(dep); + return true; + } + + let str = ""; + for (const prop of referencedPropertiesInDestructuring) { + switch (prop) { + case "url": + str += `url: ${importMetaUrl()},`; + break; + case "webpack": + str += `webpack: ${importMetaWebpackVersion()},`; + break; + default: + str += `[${JSON.stringify( + prop + )}]: ${importMetaUnknownProperty([prop])},`; + break; + } + } + const dep = new ConstDependency(`({${str}})`, metaProperty.range); dep.loc = metaProperty.loc; parser.state.module.addPresentationalDependency(dep); return true; @@ -120,10 +159,7 @@ class ImportMetaPlugin { parser.hooks.expression .for("import.meta.url") .tap(PLUGIN_NAME, expr => { - const dep = new ConstDependency( - JSON.stringify(getUrl(parser.state.module)), - expr.range - ); + const dep = new ConstDependency(importMetaUrl(), expr.range); dep.loc = expr.loc; parser.state.module.addPresentationalDependency(dep); return true; @@ -140,10 +176,6 @@ class ImportMetaPlugin { }); /// import.meta.webpack /// - const webpackVersion = parseInt( - require("../../package.json").version, - 10 - ); parser.hooks.typeof .for("import.meta.webpack") .tap( @@ -154,7 +186,7 @@ class ImportMetaPlugin { .for("import.meta.webpack") .tap( PLUGIN_NAME, - toConstantDependency(parser, JSON.stringify(webpackVersion)) + toConstantDependency(parser, importMetaWebpackVersion()) ); parser.hooks.evaluateTypeof .for("import.meta.webpack") @@ -168,9 +200,7 @@ class ImportMetaPlugin { .for("import.meta") .tap(PLUGIN_NAME, (expr, members) => { const dep = new ConstDependency( - `${Template.toNormalComment( - "unsupported import.meta." + members.join(".") - )} undefined${propertyAccess(members, 1)}`, + importMetaUnknownProperty(members), expr.range ); dep.loc = expr.loc; diff --git a/test/cases/esm/import-meta/index.js b/test/cases/esm/import-meta/index.js index 43fe084d41e..8f57a9a700f 100644 --- a/test/cases/esm/import-meta/index.js +++ b/test/cases/esm/import-meta/index.js @@ -42,5 +42,16 @@ it("should return undefined for unknown property", () => { expect(import.meta.other).toBe(undefined); if (typeof import.meta.other !== "undefined") require("fail"); expect(() => import.meta.other.other.other).toThrowError(); - // if (typeof import.meta.other.other.other !== "undefined") require("fail"); +}); + +it("should add warning on direct import.meta usage", () => { + expect(Object.keys(import.meta)).toHaveLength(0); +}); + +it("should support destructuring assignment", () => { + let version, url2, c; + ({ webpack: version } = { url: url2 } = { c } = import.meta); + expect(version).toBeTypeOf("number"); + expect(url2).toBe(url); + expect(c).toBe(undefined); }); diff --git a/test/cases/esm/import-meta/warnings.js b/test/cases/esm/import-meta/warnings.js new file mode 100644 index 00000000000..d8fc384d81d --- /dev/null +++ b/test/cases/esm/import-meta/warnings.js @@ -0,0 +1,5 @@ +module.exports = [ + [ + /Accessing import.meta directly is unsupported \(only property access or destructuring is supported\)/ + ] +];