我正在嘗試使用帶有 babel-loader 8.2.5 的 webpack v5.74.0 來轉換和打包必須與 Microsoft 的 WebBrowser 控制元件(即 IE 8 / ES3 標準)兼容的 Javascript 代碼。具體來說,WebBrowser 控制元件在遇到方法名稱也是 JS 關鍵字的 JS 代碼時會拋出“預期識別符號”錯誤,例如 Set.delete()。
這是一個小測驗用例:
專案結構
$ ls -l -R --hide=node_modules
.:
total 266
drwxr-xr-x 1 demo.user 197121 0 Oct 21 17:32 dist/
-rw-r--r-- 1 demo.user 197121 265954 Oct 21 16:56 package-lock.json
-rw-r--r-- 1 demo.user 197121 393 Oct 21 18:09 package.json
drwxr-xr-x 1 demo.user 197121 0 Oct 21 16:06 src/
-rw-r--r-- 1 demo.user 197121 917 Oct 21 17:45 webpack.prod.js
-rw-r--r-- 1 demo.user 197121 145 Oct 21 17:16 xxxbabel.config.json
./dist:
total 1
-rw-r--r-- 1 demo.user 197121 94 Oct 21 17:33 main.js
./src:
total 1
-rw-r--r-- 1 demo.user 197121 94 Oct 21 17:46 main.js
包.json:
{
"name": "webpack-test",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"build": "webpack --config=webpack.prod.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.19.3",
"@babel/preset-env": "^7.19.4",
"babel-loader": "^8.2.5",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
}
}
webpack.prod.js:
const path = require("path");
module.exports = {
entry: {
main: "./src/main.js"
},
mode: "production",
output: {
filename: "[name].js",
path: path.resolve(__dirname, "./dist"),
environment: {
arrowFunction: false // prevent top level arrow IIFE on Webpack 5
},
clean: true // clean output dir before each build
},
module: {
rules: [
{
test: /\.js$/, // transpile JS for older browsers
exclude: /node_modules/, // don't mess with node_modules
use: {
loader: "babel-loader",
options: {
"presets": [
[
'@babel/preset-env', {
targets: {
"ie": "8" // target for IE 8 ES3 for WebBrowser control
},
debug: true
}
]
], // let's us use latest JS features
//"plugins": [ "@babel/plugin-transform-member-expression-literals" ]
}
}
}
]
}
}
輸入代碼: src/main.js
這里我以 Set 物件的方法為例delete,參見
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
var d = new Set("a", "b", "c");
d["delete"]("a");
console.log("Set has a? " d.has("a"));
使用呼叫 webpack
npm run build
$ npm run build
> webpack-test@1.0.0 build
> webpack --config=webpack.prod.js
@babel/preset-env: `DEBUG` option
Using targets:
{
"ie": "8"
}
Using modules transform: auto
Using plugins:
proposal-class-static-block { ie }
proposal-private-property-in-object { ie }
proposal-class-properties { ie }
proposal-private-methods { ie }
proposal-numeric-separator { ie }
proposal-logical-assignment-operators { ie }
proposal-nullish-coalescing-operator { ie }
proposal-optional-chaining { ie }
proposal-json-strings { ie }
proposal-optional-catch-binding { ie }
transform-parameters { ie }
proposal-async-generator-functions { ie }
proposal-object-rest-spread { ie }
transform-dotall-regex { ie }
proposal-unicode-property-regex { ie }
transform-named-capturing-groups-regex { ie }
transform-async-to-generator { ie }
transform-exponentiation-operator { ie }
transform-template-literals { ie }
transform-literals { ie }
transform-function-name { ie }
transform-arrow-functions { ie }
transform-block-scoped-functions { ie < 11 }
transform-classes { ie }
transform-object-super { ie }
transform-shorthand-properties { ie }
transform-duplicate-keys { ie }
transform-computed-properties { ie }
transform-for-of { ie }
transform-sticky-regex { ie }
transform-unicode-escapes { ie }
transform-unicode-regex { ie }
transform-spread { ie }
transform-destructuring { ie }
transform-block-scoping { ie }
transform-typeof-symbol { ie }
transform-new-target { ie }
transform-regenerator { ie }
transform-member-expression-literals { ie < 9 }
transform-property-literals { ie < 9 }
transform-reserved-words { ie < 9 }
proposal-export-namespace-from { ie }
syntax-dynamic-import
syntax-top-level-await
Using polyfills: No polyfills were added, since the `useBuiltIns` option was not set.
asset main.js 94 bytes [compared for emit] [minimized] (name: main)
./src/main.js 90 bytes [built] [code generated]
webpack 5.74.0 compiled successfully in 1940 ms
webpack / babel 輸出: dist/main.js:
!function(){var a=new Set("a","b","c");a.delete("a"),console.log("Set has a? " a.has("a"))}();
注意a.delete()對 IE8 無效的呼叫。它將導致上述“預期識別符號”錯誤訊息。
預期輸出
預期輸出將與輸入相同,即對 delete 方法的呼叫應為a["delete"]().
我嘗試使用他們的 REPL 頁面單獨檢查 babel,其中代碼被正確轉換: https ://babel.dev/repl#?browsers=ie 8&build=&builtIns=false&corejs=false&spec=false&loose=true&code_lz=G4QwTgBAJhC8EDsCmB3CBlJAXAFAIhDwBoI8AjY0gYzwEoBuAKCgDookAbbJfQhoA&debugAll =false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=script&lineWrap=true&presets=env,stage-2&prettier=false&targets=&version=7.19.6&externalPlugins=&assumptions={}
因此,我認為要么組態檔不正確,要么 webpack/babel-loader 配置未正確傳遞給 babel。我將不勝感激任何解決此問題的幫助。
uj5u.com熱心網友回復:
所以我想出了解決方案。顯然這不是 babel 問題,而是之后發生的縮小。Terser(縮小器)弄亂了代碼。我可以找到正確的選項來防止 terser 用點表示法替換屬性訪問,記錄在這里: https ://github.com/terser/terser#compress-options
首先我們需要在 webpack.prod.js 中包含 terser 插件:
const TerserPlugin = require("terser-webpack-plugin");
然后在“模塊”配置之后附加一個簡潔的配置:
optimization: {
minimize: true,
minimizer: [new TerserPlugin({
terserOptions: {
compress: { properties: false },
mangle: false,
},
})],
}
完成 webpack.prod.js:
const path = require("path");
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
entry: {
main: "./src/main.js"
},
mode: "production",
output: {
filename: "[name].js",
path: path.resolve(__dirname, "./dist"),
environment: {
arrowFunction: false // prevent top level arrow IIFE on Webpack 5
},
clean: true // clean output dir before each build
},
module: {
rules: [
{
test: /\.js$/, // transpile JS for older browsers
exclude: /node_modules/, // don't mess with node_modules
use: {
loader: "babel-loader",
options: {
"presets": [
[
'@babel/preset-env', {
targets: {
"ie": "8" // target for IE 8 ES3 for WebBrowser control
},
debug: true
}
]
], // let's us use latest JS features
//"plugins": [ "@babel/plugin-transform-member-expression-literals" ]
}
}
}
]
},
optimization: {
minimize: true,
minimizer: [new TerserPlugin({
terserOptions: {
compress: { properties: false }, // important: don't rewrite property access using the dot notation, e.g. foo["bar"] → foo.bar
mangle: false,
},
})],
}
}
輸出檔案 dist/main.js 然后如預期的那樣:
$ cat dist/main.js
!function(){var d=new Set("a","b","c");d["delete"]("a"),console.log("Set has a? " d.has("a"))}();
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/519670.html
