webpack 4 問世了!
這個流行的模組打包工具進行了大規模的升級。
webpack4,有什麼更新?大幅度的效能優化,零配置和明智的預設配置。
webpack 4 ,零配置的模組打包工具
webpack是一個強力和有著很多獨特功能的工具,但是他的一大痛點在於他的配置檔案
給中大型專案提供一個配置檔案不是什麼大問題。你甚至無法離開它。然而,對於一些較小型應用來說就有點麻煩了,尤其是你在心血來潮想開始做一些好玩的app的時候。
這也是Parcel吸引人的原因
現在的好訊息是webpack 4 預設再也不需要一個配置檔案了!
webpack 4:零配置開始
建立一個目錄然後進入
mkdir webpack-4-quickstart && cd $_
複製程式碼
初始化package.json:
npm init -y
複製程式碼
安裝webpack4:
npm i webpack --save-dev
複製程式碼
我們也需要安裝另外一個包:webpack-cli
npm i webpack-cli --save-dev
複製程式碼
然後開啟package.json新增構建指令碼:
"scripts": {
"build": "webpack"
}
複製程式碼
關閉儲存
試著執行
npm run build
複製程式碼
然後我們看到
ERROR in Entry module not found: Error: Can't resolve './src' in '~/webpack-4-quickstart'
複製程式碼
webpack 4 需要在./src目錄下找一個入口檔案!如果你不知道這是什麼意思,請參考我之前的文章
簡要來說:webpack需要這個入口檔案來開始js程式碼的打包。
在以前的版本里webpack的入口檔案需要在配置檔案webpack.config.js裡指定。
但是現在不用指定了,它會預設選擇./src/index.js這個檔案。
測試這個新特性很容易,建立一個./src/index.js
:
console.log(`I'm a silly entry point`);
複製程式碼
重新構建:
npm run build
複製程式碼
你會在~/webpack-4-quickstart/dist/main.js
得到你打包後的檔案。
什麼?等一下。都不需要指定輸出檔案嗎?是的。
在webpack 4 中不需要指定入口和出口檔案。
webpack的真正本領是程式碼拆分。但是相信我,有一個零配置的工具可以加速你的程式。
所以這就是第一個新特性:他會把./src/index.js預設為入口檔案,把打包後的檔案放在./dist/main.js。
下一章後我們能看到另一個有用的特性:生產和開發模式。
Webpack 4:生產和開發模式
在webpack中擁有兩份配置檔案是常事。
一個典型的專案應該有:
- 一個開發用的配置檔案,用來定義webpack的dev server和其他東西
- 一個生產環境用的配置檔案,用來定義UglifyJSPlugin,sourcemap和其他東西。
在webpack4中你能夠不寫一行配置。
怎麼做到的?
webpack 4介紹了生產和開發模式。
實際上如果你關注過npm run build
的輸出資訊你會看到這個警告:
The ‘mode’ option has not been set. Set ‘mode’ option to ‘development’ or ‘production’ to enable defaults for this environment.
這代表什麼?我們看看。
開啟package.json檔案新增如下指令碼
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production"
}
複製程式碼
現在執行:
npm run dev
複製程式碼
檢視./dis/main.js檔案。你看到了什麼?嗯,我知道,他沒有被壓縮!
現在這樣:
npm run build
複製程式碼
現在再看,你看到什麼?一個壓縮後的檔案!
是的!
生產模式開啟了一系列額外的優化。包括minification, scope hoisting, tree-shaking等。
另一邊開發模式為速度做了優化,除了提供一個沒有壓縮的包以外沒有做額外的事。
所以這是第二個新特性:生產和開發模式。
在webpack4你不需要一行配置,只需要一個--mode選項。
webpack 4:覆蓋預設的入口/出口檔案
我喜歡webpack4的零配置,但是,如果我要覆蓋預設的入口或者出口配置要怎麼做呢?
在package.json
裡配置他們。
這是一個例子
"scripts": {
"dev": "webpack --mode development ./foo/src/js/index.js --output ./foo/main.js",
"build": "webpack --mode production ./foo/src/js/index.js --output ./foo/main.js"
}
複製程式碼
webpack 4:用Babel轉換ES6的js程式碼
現代JavaScript大多是用ES6寫的。
但是不是所有瀏覽器都知道怎麼處理ES6。我們需要做一些轉換。
這個轉換的步驟叫做transpiling。transpiling是指把ES6轉換成瀏覽器能夠識別的程式碼。
webpack本身並不知道如何去轉換,但是它有loaders。把他們想象成轉換器。
babel-loader是webpack的一個loader,可以轉換ES6以上的程式碼到ES5。
為了使用這個loader我們需要去安裝一系列的依賴。特別是:
- babel-core
- babel-loader
- babel-preset-env (for compiling Javascript ES6 code down to ES5)
來安裝吧:
npm i babel-core babel-loader babel-preset-env --save-dev
複製程式碼
下一步我們在專案目錄下建立一個.babelrc檔案用來配置Babel。
{
"presets": [
"env"
]
}
複製程式碼
在這裡我們有兩個途徑去配置babel-loader:
- 用webpack的配置檔案
- 在npm指令碼里使用
--module-bind
哦,我知道你在想什麼了。webpack4把自己定位為一個零配置的工具。為什麼我們又要寫配置檔案了呢。
webpack 4的零配置適用於:
- 入口檔案。預設是./src/index.js
- 出口檔案。預設是./dist/main.js
- 生產和開發模式(無需建立兩套配置檔案)
這就夠了。對於loaders我們仍然需要使用配置檔案。
我曾關於這件事問過Sean。在webpack4中loaders是否和webpack3中沒有區別?有計劃對這些通用的loaders比如babel-loader提供零配置嗎?
他的回答是:
在未來的版本(v4之後,可能是4.x或者5.0),我們已經開始探索預設或附加系統如何幫助我們定義這一點。我們不想要的是:把一堆東西塞到核心程式碼裡去。我們需要的是:能夠支援擴充套件。
對於現在來說你仍必須依賴webpack.config.js。
webpack 4:通過配置檔案使用babel-loader
建立一個名叫webpack.config.js
的檔案然後配置loader:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
};
複製程式碼
沒有必要去指定入口檔案除非你想指定。
下一步開啟./src/index.js然後寫一些ES6程式碼:
const arr = [1, 2, 3];
const iAmJavascriptES6 = () => console.log(...arr);
window.iAmJavascriptES6 = iAmJavascriptES6;
複製程式碼
最後打包:
npm run build
複製程式碼
然後去./dist/main.js看看轉換後的程式碼。
webpack 4:不通過配置檔案使用babel-loader
還有一種使用webpack loaders的方法。
--module-bind
選項讓你從命令列指定loaders。謝謝Cezar指出了這一點。
這個選項並不是webpack 4獨有的。3開始就有了。
你可以這樣在package.json中使用:
"scripts": {
"dev": "webpack --mode development --module-bind js=babel-loader",
"build": "webpack --mode production --module-bind js=babel-loader"
}
複製程式碼
然後你就可以開始構建了。
然後我並不是很喜歡這種方法(不喜歡太長的npm指令碼),儘管如此它很有趣。
webpack 4:在webpack 4中配置React
如果你已經安裝配置好了babel這會很簡單。
安裝React:
npm i react react-dom --save-dev
複製程式碼
新增babel-preset-react
:
npm i babel-preset-react --save-dev
複製程式碼
在.babelrc裡配置preset
{
"presets": ["env", "react"]
}
複製程式碼
這樣就可以了。
如Conner Aiken建議的你可以配置babel-loader也去載入**.jsx**檔案。這在你使用jsx副檔名的時候很有用。
開啟webpack.config.js
然後這樣配置:
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
};
複製程式碼
測試是否搭好你可以在./src/App.js
裡建立一個React元件。
import React from "react";
import ReactDOM from "react-dom";
const App = () => {
return (
<div>
<p>React here!</p>
</div>
);
};
export default App;
ReactDOM.render(<App />, document.getElementById("app"));
複製程式碼
然後在./src/idnex.js
中引入:
import App from "./App";
複製程式碼
重新構建
webpack 4:HTML外掛
webpack需要兩個額外的元件去處理HTML:html-webpack-plugin和html-loader。
新增這兩個依賴:
npm i html-webpack-plugin html-loader --save-dev
複製程式碼
然後更新webpack的配置
const HtmlWebPackPlugin = require("html-webpack-plugin");
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
})
]
};
複製程式碼
在./src/index.html
新建一個HTML檔案:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>webpack 4 quickstart</title>
</head>
<body>
<div id="app">
</div>
</body>
</html>
複製程式碼
執行:
npm run build
複製程式碼
檢視./dist
目錄。你會看到執行的結果。
沒有必要再你的HTML檔案中引入你的JavaScript:它會自動地注入進去。
在瀏覽器開啟./dist/index.html
:你可以看到React元件執行起來了!
如你所見在處理HTML上沒有什麼變化。
webpack 4仍然是一個主要目標是js的模組打包工具。
但有個將HTML作為模組的方法(HTML作為入口)。
提取CSS到檔案中
webpack不知道怎麼去提取CSS到檔案中。
在之前這是extract-text-webpack-plugin的工作。
不幸的是這個外掛在webpack 4表現並不好。
Michael Ciniawsky說:
維護extract-text-webpack-plugin是一個很大的負擔,而且這不是第一次因為這個問題使得升級webpack的主要版本變得困難。
mini-css-extract-plugin是來解決這些問題的。
提示:你需要把webpack升級到4.2.0.0,不然這個外掛無法執行!
安裝它:
npm i mini-css-extract-plugin css-loader --save-dev
複製程式碼
然後建立一個CSS檔案用來測試
/* */
/* CREATE THIS FILE IN ./src/main.css */
/* */
body {
line-height: 2;
}
複製程式碼
配置plugin和loader:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
]
};
複製程式碼
最後在入口檔案中引入CSS:
//
// PATH OF THIS FILE: ./src/index.js
//
import style from "./main.css";
複製程式碼
構建:
npm run build
複製程式碼
檢視./dist目錄,你應該能看到CSS的結果!
結論:extract-text-webpack-plugin在webpack 4中不能用了。請使用mini-css-extract-plugin。
webpack 4:webpack dev server
在你改變程式碼後執行npm run dev
?這不是個理想的做法。花幾分鐘去配置下webpack的開發服務。一旦配置了webpack dev server 它會在瀏覽器中載入你的app。
只要你改變了檔案,它會自動地重新整理瀏覽器的頁面。
安裝下面的包來搭建webpack dev server:
npm i webpack-dev-server --save-dev
複製程式碼
然後開啟package.json
調整指令碼:
"scripts": {
"start": "webpack-dev-server --mode development --open",
"build": "webpack --mode production"
}
複製程式碼
儲存關閉。
現在執行:
npm run start
複製程式碼
你就能看到webpack dev server在瀏覽器中載入你的應用了。
webpack dev server非常適合用來開發。(而且它能使得的React Dev Tools在瀏覽器中正常的工作)
webpack 4:資源
本教程在Github上的連結 => webpack-4-quickstart
我知道早就有很多webpack的列表但是這裡是我的:一系列優秀的webpack4資源 => awesome-webpack-4
這裡一定還要提一下Juho Vepsäläinen的SurviveJS webpack 4