使用 webpack 直接解析下面的檔案會出問題。
class Counter extends HTMLElement {
x = 0;
clicked() {
this.x++
window.requestAnimationFrame(this.render.bind(this))
}
constructor() {
super()
this.onclick = this.clicked.bind(this)
this.x = 0
}
connectedCallback() {
this.render()
}
render() {
this.textContent = this.x.toString()
}
}
window.customElements.define('num-counter', Counter)
報錯資訊如下:
$ npx webpack --watch
webpack is watching the files…
Hash: d8bc5ae1b88c0918c1c1
Version: webpack 4.44.2
Time: 67ms
Built at: 2020-09-26 9:00:13 ├F10: PM┤
Asset Size Chunks Chunk Names
bundle.js 3.87 KiB 0 [emitted] main
index.html 276 bytes [emitted]
Entrypoint main = bundle.js
[0] ./src/index.js 303 bytes {0} [built] [failed] [1 error]
ERROR in ./src/index.js 2:6
Module parse failed: Unexpected token (2:6)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| class Counter extends HTMLElement {
> x = 0;
|
| clicked() {
Child HtmlWebpackCompiler:
1 asset
Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
[0] ../node_modules/html-webpack-plugin/lib/loader.js!./src/template.html 505 bytes {0} [built]
報錯出在 index.js 第二行的第 6 個字元。
ERROR in ./src/index.js 2:6
也就是在下面這個地方:
class Counter extends HTMLElement {
x = 0; // ← 這裡
// ...
}
查詢得知,webpack 內部使用的 parser acorn 只支援 stage 4 階段的提案。而我這裡使用的 class (public) field declarations 的特性 目前還處於 stage 3 階段,因此出錯。這時就要藉助 babel-loader 來轉碼了。
首先安裝依賴:
$ npm install -D babel-loader @babel/core @babel/preset-env @babel/plugin-proposal-class-properties
然後配置 webpack.config.js:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
// See: https://webpack.js.org/loaders/babel-loader/
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-proposal-class-properties']
}
}
}
]
},
plugins: [
// See: https://webpack.js.org/plugins/html-webpack-plugin/
new HtmlWebpackPlugin({ template: './src/template.html' })
],
mode: 'none'
};
重新編譯,就不會有問題了。
$ npx webpack --watch
webpack is watching the files…
Hash: 651e138f726765848707
Version: webpack 4.44.2
Time: 802ms
Built at: 2020-09-26 10:31:09 ├F10: PM┤
Asset Size Chunks Chunk Names
bundle.js 8.82 KiB 0 [emitted] main
index.html 276 bytes [emitted]
Entrypoint main = bundle.js
[0] ./src/index.js 5.25 KiB {0} [built]
Child HtmlWebpackCompiler:
1 asset
Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
[0] ../node_modules/html-webpack-plugin/lib/loader.js!./src/template.html 505 bytes {0} [built]
最終得到的 bundle 檔案如下(簡要):
var Counter = /*#__PURE__*/function (_HTMLElement) {
_inherits(Counter, _HTMLElement);
var _super = _createSuper(Counter);
_createClass(Counter, [{
key: "clicked",
value: function clicked() {
this.x++;
window.requestAnimationFrame(this.render.bind(this));
}
}]);
function Counter() {
var _this;
_classCallCheck(this, Counter);
_this = _super.call(this);
_defineProperty(_assertThisInitialized(_this), "x", 0);
_this.onclick = _this.clicked.bind(_assertThisInitialized(_this));
_this.x = 0;
return _this;
}
_createClass(Counter, [{
key: "connectedCallback",
value: function connectedCallback() {
this.render();
}
}, {
key: "render",
value: function render() {
this.textContent = this.x.toString();
}
}]);
return Counter;
}( /*#__PURE__*/_wrapNativeSuper(HTMLElement));
window.customElements.define('num-counter', Counter);
Tip:
上面的 @babel/plugin-proposal-class-properties plugin 是解決問題的關鍵。如果只是配置了 babel-loader 的 presets option,依然會報錯。
$ npx webpack --watch webpack is watching the files… Hash: 2bb64eb81b2f5899f55f Version: webpack 4.44.2 Time: 748ms Built at: 2020-09-26 10:24:22 ├F10: PM┤ Asset Size Chunks Chunk Names bundle.js 7.78 KiB 0 [emitted] main index.html 276 bytes [emitted] Entrypoint main = bundle.js [0] ./src/index.js 4.2 KiB {0} [built] [failed] [1 error] ERROR in ./src/index.js Module build failed (from ../node_modules/babel-loader/lib/index.js): SyntaxError: E:\projects\tc39-proposal-demos\proposal-class-fields\src\index.js: Support for the experimental syntax 'classProperties' isn't currently enabled (2:7): 1 | class Counter extends HTMLElement { > 2 | x = 0; | ^ 3 | 4 | clicked() { 5 | this.x++ Add @babel/plugin-proposal-class-properties (https://git.io/vb4SL) to the 'plugins' section of your Babel config to enable transformation. If you want to leave it as-is, add @babel/plugin-syntax-class-properties (https://git.io/vb4yQ) to the 'plugins' section to enable parsing. at Parser._raise (E:\projects\tc39-proposal-demos\node_modules\@babel\parser\lib\index.js:766:17)
(完)
本作品採用《CC 協議》,轉載必須註明作者和本文連結