接觸webpack是好久之前的事情了,最近看了下webpack沒想到都到4了。
webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module bundler).
會創建1個依賴關系圖(dependency graph),包含所有依賴的模塊,然后將模塊打包成1個或多個bundle.
webpack4 仍然支持高度可配,但完全可以不用配置文件了(基於mode)。
安裝
淘寶源:npm config set registry https://registry.npm.taobao.org
升級npm:npm i npm -g
安裝webpack:npm i -D webpack webpack-cli webpack-dev-server
運行webpack:npx webpack
(Node 8.2+ 版本提供的npx
命令)
基本特性
核心配置:
- 入口(entry):
- 輸出(output):
- loader:
- 插件(plugins):
Entry
入口起點(entry point)指示 webpack 應該使用哪個模塊,來作為構建其內部依賴圖的開始。
可以通過在 webpack 配置中配置 entry 屬性,來指定一個入口起點(或多個入口起點)。默認值為 ./src/index.js
webpack.config.js
module.exports = {
entry: {
main: './src/index.js'
},
};
Output
output 屬性告訴 webpack 在哪里輸出它所創建的 bundles,以及如何命名這些文件,默認值為./dist/[name].js
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
}
};
Loader
loader 讓 webpack 能夠去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。
loaders 有2個核心參數:
- test 屬性,用於標識出需要轉換的某個或某些文件。
- use 屬性,表示進行轉換時,應該使用哪個 loader。
const path = require('path');
const config = {
output: {
filename: 'bundle.js'
},
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
}
};
module.exports = config;
Plugins
插件的范圍包括,從打包優化和壓縮,一直到重新定義環境中的變量。插件接口功能極其強大,可以用來處理各種各樣的任務。
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通過 npm 安裝
const webpack = require('webpack'); // 用於訪問內置插件
const config = {
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;
Mode
通過選擇 development 或 production 之中的一個,來設置 mode 參數
webpack.config.js
module.exports = {
mode: 'production'
};
mode.js
// webpack.development.config.js
module.exports = {
+ mode: 'development'
- plugins: [
- new webpack.NamedModulesPlugin(),
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
- ]
}
// webpack.production.config.js
module.exports = {
+ mode: 'production',
- plugins: [
- new UglifyJsPlugin(/* ... */),
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
- new webpack.optimize.ModuleConcatenationPlugin(),
- new webpack.NoEmitOnErrorsPlugin()
- ]
}
常用插件
HtmlWebpackPlugin:
const HtmlWebpackPlugin = require('html-webpack-plugin');
new HtmlWebpackPlugin({ template: 'src/index.html', minify: true, hash: true })
CleanWebpackPlugin:
const CleanWebpackPlugin = require('clean-webpack-plugin');
new CleanWebpackPlugin(['dist'])
MiniCssExtractPlugin(ExtractTextPlugin):
new MiniCssExtractPlugin({ filename: "[name].css",chunkFilename: "[id].css" })
module: {
rules: [{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]}
]
}
SplitChunksPlugin:
module.exports = {
mode: 'development',
entry: {
main: './src/index.js',
vendors: 'lodash'
},
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "initial"
}
}
}
}
}
配置示例
package
package.json
{
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --open",
"build": "webpack --config webpack.prod.js"
},
"devDependencies": {
"babel-loader": "^7.1.4",
"babel-preset-react": "^6.24.1",
"babel-plugin-import": "^1.7.0",
"clean-webpack-plugin": "^0.1.19",
"css-loader": "^0.28.11",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.4.0",
"webpack": "^4.8.3",
"webpack-cli": "^2.1.3",
"webpack-dev-server": "^3.1.4"
},
"dependencies": {
"antd": "^3.5.2",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"express": "^4.16.3",
"lodash": "^4.17.10",
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-loadable": "^5.4.0",
"react-redux": "^5.0.7",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"redux": "^4.0.0",
"redux-logger": "^3.0.6",
"redux-promise": "^0.6.0",
"redux-saga": "^0.16.0",
"redux-thunk": "^2.2.0"
}
}
開發環境
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js',
},
devtool: 'inline-source-map',
devServer: {
contentBase: './dist'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
module: {
rules: [{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
}, {
test: /\.(js|jsx)$/,
loader: 'babel-loader',
options: {
presets: ['react'],
plugins: [
["import", { "libraryName": "antd", "style": "css" }]
]
},
exclude: /node_modules/
}]
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({ minify: true, hash: true }),
new MiniCssExtractPlugin({ filename: "[name].css", chunkFilename: "[id].css" })
],
optimization: {
splitChunks: {
cacheGroups: {
common: {
test: /[\\/]node_modules[\\/]/,
name: "common",
chunks: "initial",
enforce: true
},
}
}
}
};
生產環境
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require('path');
module.exports = {
mode: 'production',
entry: {
main: './src/index.js',
},
devtool: 'source-map',
devServer: {
contentBase: './dist',
host: '192.168.0.75'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
module: {
rules: [{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
}, {
test: /\.(js|jsx)$/,
loader: 'babel-loader',
options: {
presets: ['react'],
plugins: []
},
exclude: /node_modules/
}]
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({ template: 'src/index.html', minify: true, hash: true }),
new MiniCssExtractPlugin({ filename: "[name].css", chunkFilename: "[id].css" })
],
externals: {
lodash: '_',
react: 'React',
'react-dom': 'ReactDOM',
antd: 'antd'
},
optimization: {
splitChunks: {
cacheGroups: {
common: {
test: /[\\/]node_modules[\\/]/,
name: "common",
chunks: "initial",
enforce: true
},
}
}
}
};