webpack4:從0配置到專案搭建
webpack4:從0配置到專案搭建
webpack4釋出以來,我寫專案都是用腳手架,即使再簡單的專案,真的是really shame。。雖然道聽途說了很多 webpack4 的特性,卻沒有嘗試過,因為它給人的感覺就是,em...很難。但是今天我從最簡單的部分開始,一點點搭建起一個專案。
0配置,配置了什麼
讓我們從0開始,新建一個專案,在終端執行以下語句:
mkdir webpack-4-quickstart && cd webpack-4-quickstart npm init -y npm i webpack --save-dev npm i webpack-cli --save-dev
修改程式碼 package.json
中 scripts
部分:
"scripts": {
"build": "webpack"
}
現在,我們的 package.json
是這樣的:
{ "name": "webpack-4-quickstart", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "webpack" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^4.14.0", "webpack-cli": "^3.0.8" } }
此時,我們執行 npm run build
, 會給出以下提示/錯誤:
- error: 沒有入口檔案
- warning: 建議設定
mode
選項
entry & output
為了解決第一個問題,我們嘗試新建 src/index.js
:
console.log(`I'm a entry point`);
此時再次執行 npm run build
,成功打包出了 dist/main.js
,因此我們可以得知:
webpack4 more配置了 entry(入口)
src/index.js
和output(出口)dist/main.js
當然,如果你想覆蓋這個配置(比如修改為 ./foo/src/js/index.js
),可以在 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"
}
production & development
webpack4 之前,我們寫一個專案起碼會設定兩種型別檔案:
- 用於開發環境的webpack.dev.conf.js,定義 webpack 啟動的伺服器等
- 用於生產環境的webpack.prod.conf.js,定義UglifyJSPlugin或其他配置等
而 webpack4 的 mode
給出了兩種配置:development
和 production
。
我們修改 package.json
中 scripts
部分:
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production"
}
我們分別執行 npm run dev
和 npm run build
執行 npm run dev
打包的是未壓縮的程式碼,而 npm run build
是壓縮後的程式碼。
- 生產模式下:啟用了 程式碼壓縮、作用域提升(scope hoisting)、 tree-shaking,使程式碼最精簡
- 開發模式下:相較於更小體積的程式碼,提供的是打包速度上的優化
總結
webpack 4 的零配置主要應用於:
entry
預設設定為./src/index.js
output
預設設定為./dist/main.js
production
和development
兩種模式
專案搭建
專案搭建,我們對webpack的訴求是:
- js的處理:轉換 ES6 程式碼,解決瀏覽器相容問題
- css的處理:編譯css,自動新增字首,抽取css到獨立檔案
- html的處理:複製並壓縮html檔案
- dist的清理:打包前清理源目錄檔案
- assets的處理:靜態資源處理
- server的啟用:development 模式下啟動伺服器並實時重新整理
轉換 ES6 程式碼,解決瀏覽器相容問題
用 babel 轉換 ES6 程式碼
用 babel 轉換 ES6 程式碼需要使用到 babel-loader ,我們需要安裝一系列的依賴:
npm i babel-core babel-loader babel-preset-env --save-dev
然後在根目錄新建一個babel配置檔案 .babelrc
:
{
"presets": [
"env"
]
}
那麼如何將配置用於webpack打包中?
- 新建一個 webpack 的配置檔案
- 在 npm scripts 中使用
--module-bind
-
使用 webpack 的配置檔案的方法:
新建
webpack.config.js
:module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader" } } ] } }
-
在 npm scripts 中配置的方法:
"scripts": {
"dev": "webpack --mode development --module-bind js=babel-loader",
"build": "webpack --mode production --module-bind js=babel-loader"
}
使用 babel-polyfill 解決相容性問題
然而瀏覽器依然不支援一些語法的使用,導致相容性問題,我們用 babel-polyfill
解決:
npm i babel-polyfill babel-plugin-transform-runtime --save-dev
.babelrc
新增配置:
{
"presets": [
"env"
],
"plugins": [
"transform-runtime"
]
}
最後在 webpack.config.js
中將 babel-polyfill
加到你的 entry 陣列中:
const path = require('path');
module.exports = {
entry: [
"babel-polyfill",
path.join(__dirname, './src/index.js')
],
// ...
};
編譯css,自動新增字首,抽取css到獨立檔案
webpack 並不會主動將你的css程式碼提取到一個檔案,過去我們使用 extract-text-webpack-plugin
,在webpack4中我們使用mini-css-extract-plugin來解決這個問題。
postcss-loader 用於新增瀏覽器字首,相關配置我喜歡在根目錄新建 postcss.config.js
配置
npm i mini-css-extract-plugin css-loader --save-dev
npm i style-loader postcss-loader --save-dev
// webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = (env, argv) => {
const devMode = argv.mode !== 'production'
return {
module: {
rules: [
// ...,
{
test: /\.css$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
},
]
},
plugins: [
// ...,
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
]
}
}
// postcss.config.js
module.exports = {
plugins: {
autoprefixer: {}
}
}
複製並壓縮html檔案 html-webpack-plugin
npm i html-webpack-plugin html-loader --save-dev
// webpack.config.js
const HtmlWebPackPlugin = require("html-webpack-plugin");
module.exports = {
module: {
rules: [
// ...,
{
test: /\.html$/,
use: [{
loader: "html-loader",
options: {
minimize: true
}
}]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
})
]
};
打包前清理源目錄檔案 clean-webpack-plugin
每次打包,都會生成專案的靜態資源,隨著某些檔案的增刪,我們的 dist 目錄下可能產生一些不再使用的靜態資源,webpack並不會自動判斷哪些是需要的資源,為了不讓這些舊檔案也部署到生產環境上佔用空間,所以在 webpack 打包前最好能清理 dist 目錄。
npm install clean-webpack-plugin --save-dev
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin(['dist']),
]
};
靜態資源處理 file-loader
npm install file-loader --save-dev
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {}
}
]
}
]
}
}
development 模式下啟動伺服器並實時重新整理 webpack-dev-server
npm i webpack-dev-server --save-dev
package.json
"scripts": {
"start": "webpack-dev-server --mode development --open",
"build": "webpack --mode production"
}
使用 webpack 4 建立 react 專案
現在我們模仿 create-react-app 的結構,自己搭建一個 react 專案,並且用less預編譯:
├── public
│ └── index.html # html 模板
├── src
│ ├── assets # 靜態資源
│ │ └── logo.png
│ ├── components # 元件
│ │ └── App.js
│ ├── index.js # 入口檔案
│ └── styles
│ └── index.less
├── .babelrc
├── package-lock.json
├── package.json
├── postcss.config.js
└── webpack.config.js
在以上的基礎(專案搭建部分),再安裝react相關模組及less模組:
npm i react react-dom --save
npm i babel-preset-react --save-dev
npm i less less-loader --save-dev
修改 .babelrc
:
{
"presets": ["env", "react"]
}
修改 webpack.config.js
:
// webpack.config.js
const path = require('path');
module.exports = (env, argv) => {
const devMode = argv.mode !== 'production'
return {
entry: [
"babel-polyfill",
path.join(__dirname, './src/index.js')
],
devServer: {
port: 3000, //埠號
},
module: {
rules: [
// ...
// 處理react
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
// 處理less
{
test: /\.less$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'less-loader',
]
}
]
}
}
};
基本上搭建完這個專案了,如果你想看完整程式碼
使用 webpack 4 建立 vue 專案
同樣地,我們模仿 vue-cli 的結構,自己搭建一個 vue 專案,這次我們的css預編譯語言用 scss
:
├── public
│ └── index.html # html 模板
├── src
│ ├── assets # 靜態資源
│ │ └── logo.png
│ ├── components # 元件
│ │ └── App.vue
│ ├── main.js # 入口檔案
│ ├── main.js # 入口檔案
│ └── styles
│ └── index.scss
├── .babelrc
├── package-lock.json
├── package.json
├── postcss.config.js
└── webpack.config.js
在以上的基礎(專案搭建部分),再安裝vue相關模組及sass模組:
npm i vue --save
npm i vue-loader vue-template-compiler --save-dev
npm i node-sass sass-loader --save-dev
// webpack.config.js
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = (env, argv) => {
const devMode = argv.mode !== 'production'
return {
entry: [
"babel-polyfill",
path.join(__dirname, './src/main.js')
],
module: {
rules: [
// ...
// 解析vue
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {}
}
},
// 處理scss
{
test: /\.scss$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
]
}
]
},
plugins: [
// ...
new VueLoaderPlugin()
]
}
};
一個簡易的 vue-cli 也搭建完成,如果你想看完整程式碼