add warning on unsupported environment

in case of async/await check that environment support async functions
This commit is contained in:
Ivan Kopeykin 2022-04-01 16:39:51 +03:00
parent 2c200d1656
commit d3086f3979
24 changed files with 183 additions and 7 deletions

View File

@ -2181,6 +2181,10 @@ export interface Environment {
* The environment supports arrow functions ('() => { ... }').
*/
arrowFunction?: boolean;
/**
* The environment supports async functions ('async () => { ... }').
*/
asyncFunction?: boolean;
/**
* The environment supports BigInt as literal (123n).
*/

View File

@ -479,6 +479,7 @@ class ExternalModule extends Module {
}
} else {
this.buildMeta.async = true;
this.buildMeta.asyncReason = 'externalType="module"';
if (!Array.isArray(request) || request.length === 1) {
this.buildMeta.exportsType = "namespace";
canMangle = false;
@ -488,9 +489,11 @@ class ExternalModule extends Module {
case "script":
case "promise":
this.buildMeta.async = true;
this.buildMeta.asyncReason = `externalType="${externalType}"`;
break;
case "import":
this.buildMeta.async = true;
this.buildMeta.asyncReason = 'externalType="import"';
if (!Array.isArray(request) || request.length === 1) {
this.buildMeta.exportsType = "namespace";
canMangle = false;

View File

@ -92,6 +92,7 @@ const makeSerializable = require("./util/makeSerializable");
* @property {(false | "redirect" | "redirect-warn")=} defaultObject
* @property {boolean=} strictHarmonyModule
* @property {boolean=} async
* @property {string=} asyncReason
* @property {boolean=} sideEffectFree
*/

View File

@ -102,6 +102,10 @@ class RuntimeTemplate {
return this.outputOptions.environment.arrowFunction;
}
supportsAsyncFunction() {
return this.outputOptions.environment.asyncFunction;
}
supportsOptionalChaining() {
return this.outputOptions.environment.optionalChaining;
}

View File

@ -5,10 +5,13 @@
"use strict";
const WebpackError = require("../WebpackError");
const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
const { contextify } = require("../util/identifier");
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../NormalModule")} NormalModule */
class InferAsyncModulesPlugin {
/**
@ -18,6 +21,9 @@ class InferAsyncModulesPlugin {
*/
apply(compiler) {
compiler.hooks.compilation.tap("InferAsyncModulesPlugin", compilation => {
const asyncAwaitUnsupported =
compilation.runtimeTemplate.supportsAsyncFunction() === false;
const asyncReasons = [];
const { moduleGraph } = compilation;
compilation.hooks.finishModules.tap(
"InferAsyncModulesPlugin",
@ -27,6 +33,15 @@ class InferAsyncModulesPlugin {
for (const module of modules) {
if (module.buildMeta && module.buildMeta.async) {
queue.add(module);
if (asyncAwaitUnsupported && "userRequest" in module) {
asyncReasons.push(
`- ${contextify(
compiler.context,
/** @type {NormalModule} */ (module).userRequest,
compiler
)} (${module.buildMeta.asyncReason || "unknown reason"})`
);
}
}
}
for (const module of queue) {
@ -46,6 +61,16 @@ class InferAsyncModulesPlugin {
}
}
}
if (asyncReasons.length) {
const warning = new WebpackError(
"Output environment does not support async/await"
);
warning.details = `List of async modules:\n${asyncReasons.join(
"\n"
)}`;
compilation.warnings.push(warning);
}
}
);
});

View File

@ -170,6 +170,25 @@ const resolve = browsers => {
kaios: [2, 5],
node: [6, 0]
}),
asyncFunction: rawChecker({
chrome: 55,
and_chr: 55,
edge: 15,
firefox: 52,
and_ff: 52,
// ie: Not supported,
opera: 42,
op_mob: 42,
safari: 11,
ios_saf: 11,
samsung: [6, 0],
android: 55,
// and_qq: Not supported,
// baidu: Not supported,
and_uc: [12, 12],
// kaios: Not supported,
node: [7, 6]
}),
forOf: rawChecker({
chrome: 38,
and_chr: 38,

View File

@ -921,6 +921,11 @@ const applyOutputDefaults = (
"arrowFunction",
() => tp && optimistic(tp.arrowFunction)
);
F(
output.environment,
"asyncFunction",
() => tp && optimistic(tp.asyncFunction)
);
F(output.environment, "const", () => tp && optimistic(tp.const));
F(
output.environment,

View File

@ -54,6 +54,7 @@ const getDefaultTarget = context => {
* @property {boolean | null} bigIntLiteral big int literal syntax is available
* @property {boolean | null} const const and let variable declarations are available
* @property {boolean | null} arrowFunction arrow functions are available
* @property {boolean | null} asyncFunction async functions are available
* @property {boolean | null} forOf for of iteration is available
* @property {boolean | null} destructuring destructuring is available
* @property {boolean | null} dynamicImport async import() is available
@ -172,6 +173,7 @@ You can also more options via the 'target' option: 'browserslist' / 'browserslis
templateLiteral: v(4),
optionalChaining: v(14),
arrowFunction: v(6),
asyncFunction: v(7, 6),
forOf: v(5),
destructuring: v(6),
bigIntLiteral: v(10, 4),
@ -213,6 +215,7 @@ You can also more options via the 'target' option: 'browserslist' / 'browserslis
templateLiteral: v(1, 1),
optionalChaining: v(8),
arrowFunction: v(1, 1),
asyncFunction: v(1, 7),
forOf: v(0, 36),
destructuring: v(1, 1),
bigIntLiteral: v(4),
@ -250,6 +253,7 @@ You can also more options via the 'target' option: 'browserslist' / 'browserslis
templateLiteral: v(0, 13),
optionalChaining: v(0, 44),
arrowFunction: v(0, 15),
asyncFunction: v(0, 19),
forOf: v(0, 13),
destructuring: v(0, 15),
bigIntLiteral: v(0, 32),
@ -271,6 +275,7 @@ You can also more options via the 'target' option: 'browserslist' / 'browserslis
templateLiteral: v >= 2015,
optionalChaining: v >= 2020,
arrowFunction: v >= 2015,
asyncFunction: v >= 2017,
forOf: v >= 2015,
destructuring: v >= 2015,
module: v >= 2015,

View File

@ -61,6 +61,7 @@ module.exports = class HarmonyDetectionParserPlugin {
);
}
module.buildMeta.async = true;
module.buildMeta.asyncReason = "top-level-await";
});
const skipInHarmony = () => {

View File

@ -43,6 +43,7 @@ class WebAssemblyParser extends Parser {
state.module.buildInfo.strict = true;
state.module.buildMeta.exportsType = "namespace";
state.module.buildMeta.async = true;
state.module.buildMeta.asyncReason = "async wasm";
// parse it
const program = decode(source, decoderOpts);

File diff suppressed because one or more lines are too long

View File

@ -723,6 +723,10 @@
"description": "The environment supports arrow functions ('() => { ... }').",
"type": "boolean"
},
"asyncFunction": {
"description": "The environment supports async functions ('async () => { ... }').",
"type": "boolean"
},
"bigIntLiteral": {
"description": "The environment supports BigInt as literal (123n).",
"type": "boolean"

View File

@ -323,6 +323,7 @@ describe("snapshots", () => {
],
"environment": Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": undefined,
"const": true,
"destructuring": true,
@ -1972,6 +1973,7 @@ describe("snapshots", () => {
+ "devtoolNamespace": "browserslist-test",
@@ ... @@
- "arrowFunction": true,
- "asyncFunction": true,
- "bigIntLiteral": undefined,
- "const": true,
- "destructuring": true,
@ -1979,6 +1981,7 @@ describe("snapshots", () => {
- "forOf": true,
- "module": undefined,
+ "arrowFunction": false,
+ "asyncFunction": false,
+ "bigIntLiteral": false,
+ "const": false,
+ "destructuring": false,

View File

@ -5551,6 +5551,19 @@ Object {
"multiple": false,
"simpleType": "boolean",
},
"output-environment-async-function": Object {
"configs": Array [
Object {
"description": "The environment supports async functions ('async () => { ... }').",
"multiple": false,
"path": "output.environment.asyncFunction",
"type": "boolean",
},
],
"description": "The environment supports async functions ('async () => { ... }').",
"multiple": false,
"simpleType": "boolean",
},
"output-environment-big-int-literal": Object {
"configs": Array [
Object {

View File

@ -482,6 +482,22 @@ all:
all (webpack x.x.x) compiled successfully"
`;
exports[`StatsTestCases should print correct stats for async-unsupported 1`] = `
"asset main.js 7.6 KiB [emitted] (name: main)
runtime modules 3.26 KiB 4 modules
built modules 191 bytes [built]
./index.js 106 bytes [built] [code generated]
external \\"Promise.resolve()\\" 42 bytes [built] [code generated]
./a.js 43 bytes [built] [code generated]
WARNING in Output environment does not support async/await
List of async modules:
- aaa (externalType=\\"promise\\")
- ./a.js (top-level-await)
webpack x.x.x compiled with 1 warning in X ms"
`;
exports[`StatsTestCases should print correct stats for child-compiler-apply-entry-option 1`] = `
"asset child.js 84 bytes [emitted]
asset parent.js 84 bytes [emitted] (name: parent)
@ -4593,12 +4609,12 @@ exports[`StatsTestCases should print correct stats for wasm-explorer-examples-sy
asset 517.bundle.js 243 bytes [emitted]
asset 20.bundle.js 241 bytes [emitted]
assets by path *.wasm 1.37 KiB
asset e3f145b183228cc640d7.module.wasm 531 bytes [emitted] [immutable]
asset 82d524821ee70d495948.module.wasm 290 bytes [emitted] [immutable]
asset ea450800640f54975338.module.wasm 156 bytes [emitted] [immutable]
asset ebbf27083d239c1ad5e3.module.wasm 154 bytes [emitted] [immutable]
asset ee97efb6a05a4e504238.module.wasm 154 bytes [emitted] [immutable]
asset 0301cb3f9f4151b567f5.module.wasm 120 bytes [emitted] [immutable]
asset d92334cc69c2ccd8b540.module.wasm 531 bytes [emitted] [immutable]
asset 645aa0483e52ace8e4fd.module.wasm 290 bytes [emitted] [immutable]
asset 46179256c558742d41d7.module.wasm 156 bytes [emitted] [immutable]
asset 1a7c48f2600cf2f47bc2.module.wasm 154 bytes [emitted] [immutable]
asset 71d4728d83eae16edec5.module.wasm 154 bytes [emitted] [immutable]
asset 35348d4020d7103dc072.module.wasm 120 bytes [emitted] [immutable]
chunk (runtime: main) 20.bundle.js 50 bytes (javascript) 531 bytes (webassembly) [rendered]
./duff.wasm 50 bytes (javascript) 531 bytes (webassembly) [built] [code generated]
chunk (runtime: main) bundle.js (main) 586 bytes (javascript) 9.49 KiB (runtime) [entry] [rendered]

View File

@ -3,6 +3,7 @@
exports[`browserslist target ["and_chr 80"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": true,
"const": true,
@ -32,6 +33,7 @@ Object {
exports[`browserslist target ["and_ff 68"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": true,
"const": true,
@ -61,6 +63,7 @@ Object {
exports[`browserslist target ["and_qq 10.4"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": true,
"const": true,
@ -90,6 +93,7 @@ Object {
exports[`browserslist target ["and_uc 12.12"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": false,
"browser": true,
"const": true,
@ -119,6 +123,7 @@ Object {
exports[`browserslist target ["android 4"] 1`] = `
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": true,
"const": false,
@ -148,6 +153,7 @@ Object {
exports[`browserslist target ["android 4.1"] 1`] = `
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": true,
"const": false,
@ -177,6 +183,7 @@ Object {
exports[`browserslist target ["android 4.4.3-4.4.4"] 1`] = `
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": true,
"const": false,
@ -206,6 +213,7 @@ Object {
exports[`browserslist target ["android 81"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": true,
"const": true,
@ -235,6 +243,7 @@ Object {
exports[`browserslist target ["baidu 7.12"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": true,
"const": false,
@ -264,6 +273,7 @@ Object {
exports[`browserslist target ["bb 10"] 1`] = `
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": true,
"const": false,
@ -293,6 +303,7 @@ Object {
exports[`browserslist target ["chrome 80","node 12.19.0"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": null,
"const": true,
@ -322,6 +333,7 @@ Object {
exports[`browserslist target ["chrome 80"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": true,
"const": true,
@ -351,6 +363,7 @@ Object {
exports[`browserslist target ["edge 79"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": true,
"const": true,
@ -380,6 +393,7 @@ Object {
exports[`browserslist target ["firefox 68"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": true,
"const": true,
@ -409,6 +423,7 @@ Object {
exports[`browserslist target ["firefox 80","chrome 80"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": true,
"const": true,
@ -438,6 +453,7 @@ Object {
exports[`browserslist target ["ie 11"] 1`] = `
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": true,
"const": false,
@ -467,6 +483,7 @@ Object {
exports[`browserslist target ["ie_mob 11"] 1`] = `
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": true,
"const": false,
@ -496,6 +513,7 @@ Object {
exports[`browserslist target ["ios_saf 12.0-12.1"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": false,
"browser": true,
"const": true,
@ -525,6 +543,7 @@ Object {
exports[`browserslist target ["kaios 2.5"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": true,
"const": true,
@ -554,6 +573,7 @@ Object {
exports[`browserslist target ["node 0.10.0"] 1`] = `
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": false,
"const": false,
@ -583,6 +603,7 @@ Object {
exports[`browserslist target ["node 0.12.0"] 1`] = `
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": false,
"const": false,
@ -612,6 +633,7 @@ Object {
exports[`browserslist target ["node 10.0.0"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": false,
"browser": false,
"const": true,
@ -641,6 +663,7 @@ Object {
exports[`browserslist target ["node 10.17.0"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": false,
"const": true,
@ -670,6 +693,7 @@ Object {
exports[`browserslist target ["node 12.19.0"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": false,
"const": true,
@ -699,6 +723,7 @@ Object {
exports[`browserslist target ["op_mini all"] 1`] = `
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": true,
"const": false,
@ -728,6 +753,7 @@ Object {
exports[`browserslist target ["op_mob 54"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": true,
"const": true,
@ -757,6 +783,7 @@ Object {
exports[`browserslist target ["opera 54"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": true,
"const": true,
@ -786,6 +813,7 @@ Object {
exports[`browserslist target ["safari 10"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": true,
"const": false,
@ -815,6 +843,7 @@ Object {
exports[`browserslist target ["safari 11"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": false,
"browser": true,
"const": true,
@ -844,6 +873,7 @@ Object {
exports[`browserslist target ["safari 12.0"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": false,
"browser": true,
"const": true,
@ -873,6 +903,7 @@ Object {
exports[`browserslist target ["safari 12.1"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": false,
"browser": true,
"const": true,
@ -902,6 +933,7 @@ Object {
exports[`browserslist target ["safari 13"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": false,
"browser": true,
"const": true,
@ -931,6 +963,7 @@ Object {
exports[`browserslist target ["safari TP"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": true,
"const": true,
@ -960,6 +993,7 @@ Object {
exports[`browserslist target ["samsung 4"] 1`] = `
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": true,
"const": false,
@ -989,6 +1023,7 @@ Object {
exports[`browserslist target ["samsung 9.2"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": true,
"const": true,
@ -1018,6 +1053,7 @@ Object {
exports[`browserslist target ["samsung 11.1-11.2"] 1`] = `
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"browser": true,
"const": true,
@ -1047,6 +1083,7 @@ Object {
exports[`browserslist target ["unknown 50"] 1`] = `
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"browser": true,
"const": false,

View File

@ -9,6 +9,7 @@ module.exports = {
expect(compilation.outputOptions.environment).toMatchInlineSnapshot(`
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"const": false,
"destructuring": false,

View File

@ -9,6 +9,7 @@ module.exports = {
expect(compilation.outputOptions.environment).toMatchInlineSnapshot(`
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"const": false,
"destructuring": false,

View File

@ -7,6 +7,7 @@ module.exports = {
expect(compilation.outputOptions.environment).toMatchInlineSnapshot(`
Object {
"arrowFunction": false,
"asyncFunction": false,
"bigIntLiteral": false,
"const": false,
"destructuring": false,

View File

@ -7,6 +7,7 @@ module.exports = {
expect(compilation.outputOptions.environment).toMatchInlineSnapshot(`
Object {
"arrowFunction": true,
"asyncFunction": true,
"bigIntLiteral": true,
"const": true,
"destructuring": true,

View File

@ -0,0 +1,2 @@
await Promise.resolve();
export default 1;

View File

@ -0,0 +1,6 @@
import aaa from "aaa";
import a from "./a";
it("should compile and run", () => {
expect(a).toBe(1);
});

View File

@ -0,0 +1,16 @@
/** @type {import("../../../").Configuration} */
module.exports = {
mode: "production",
target: ["web", "es5"],
entry: "./index",
experiments: {
topLevelAwait: true
},
externals: {
aaa: "promise Promise.resolve()"
},
stats: {
preset: "all",
errorDetails: true
}
};

7
types.d.ts vendored
View File

@ -3346,6 +3346,11 @@ declare interface Environment {
*/
arrowFunction?: boolean;
/**
* The environment supports async functions ('async () => { ... }').
*/
asyncFunction?: boolean;
/**
* The environment supports BigInt as literal (123n).
*/
@ -5724,6 +5729,7 @@ declare interface KnownBuildMeta {
defaultObject?: false | "redirect" | "redirect-warn";
strictHarmonyModule?: boolean;
async?: boolean;
asyncReason?: string;
sideEffectFree?: boolean;
}
declare interface KnownCreateStatsOptionsContext {
@ -10301,6 +10307,7 @@ declare abstract class RuntimeTemplate {
isModule(): undefined | boolean;
supportsConst(): undefined | boolean;
supportsArrowFunction(): undefined | boolean;
supportsAsyncFunction(): undefined | boolean;
supportsOptionalChaining(): undefined | boolean;
supportsForOf(): undefined | boolean;
supportsDestructuring(): undefined | boolean;