以后公司前端新項目 webpack 可以選擇使用這一套通用配置,該配置滿足了一下諸多功能。
使用者可以自己定義一些 loader 以及 plugin 以滿足日常開發需要,在下面給出詳細的注釋以便理解與使用。(開發時可以把注釋刪掉)
- webpack.base.js
// webpack.base.js用於通用的 webpack 配置
// 自動適配瀏覽器前綴
const autoprefixer = require('autoprefixer');
// 用於多頁面入口打包,
const glob = require('glob');
// 獲取路徑
const path = require('path');
// 自動清除輸出目錄插件
const CleanWebpackPlugin = require('clean-webpack-plugin');
// webpack 打包出錯 terminal log 插件
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
// 引入外部資源,申生成入口插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 將 CSS 提取為獨立的文件的插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 獲取項目根目錄
const projectRoot = process.cwd();
// 多頁面應用入口程序,通過匹配獲取對應頁面入口,單頁面可以直接定義 entry 就行
const setMPA = () => {
const entry = {};
const htmlWebpackPlugins = [];
const entryFiles = glob.sync(path.join(projectRoot, './src/*/index.js'));
Object.keys(entryFiles)
.map((index) => {
const entryFile = entryFiles[index];
// '/Users/buzhuo/my-project/src/index/index.js'
const match = entryFile.match(/src\/(.*)\/index\.js/);
const pageName = match && match[1];
entry[pageName] = entryFile;
return htmlWebpackPlugins.push(
new HtmlWebpackPlugin({
inlineSource: '.css$',
template: path.join(projectRoot, `./src/${pageName}/index.html`),
filename: `${pageName}.html`,
chunks: ['vendors', pageName],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false,
},
})
);
});
// 返回入口以及入口對應的 htmlWebpackPlugins
return {
entry,
htmlWebpackPlugins,
};
};
const { entry, htmlWebpackPlugins } = setMPA();
module.exports = {
entry: entry,
output: {
path: path.join(projectRoot, 'dist'),
filename: '[name]_[chunkhash:8].js'
},
module: {
rules: [
{
test: /.js$/,
use: [
{
loader: 'babel-loader'
}
],
},
{
test: /.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
],
},
{
test: /.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
{
// CSS預處理
loader: 'postcss-loader',
options: {
plugins: () => [
autoprefixer({
browsers: ['last 2 version', '>1%', 'ios 7'],
}),
],
},
},
{
// px 自動轉換為 rem 移動端,若無移動端需求該 loader 可刪去
loader: 'px2rem-loader',
options: {
remUnit: 75,
remPrecision: 8,
},
},
],
},
{
test: /.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]_[hash:8].[ext]',
},
},
],
},
{
test: /.(woff|woff2|eot|ttf|otf)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]_[hash:8][ext]',
},
},
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css',
}),
new CleanWebpackPlugin(),
new FriendlyErrorsWebpackPlugin(),
function errorPlugin() {
this.hooks.done.tap('done', (stats) => {
if (stats.compilation.errors && stats.compilation.errors.length && process.argv.indexOf('--watch') === -1) {
process.exit(1);
}
});
},
].concat(htmlWebpackPlugins),
// webpack 在打包時僅出錯才會輸出到 terminal,具體參數可到https://webpack.js.org/查看
stats: 'errors-only',
};
- webpack.dev.js
// merge 用來合並 webpack.base.js 與 webpack.dev.js
const merge = require('webpack-merge');
const webpack = require('webpack');
const baseConfig = require('./webpack.base');
const devConfig = {
mode: 'production',
plugins: [
// 生產環境下開啟熱加載插件
new webpack.HotModuleReplacementPlugin(),
],
devServer: {
// 指定 devServer 相關,在此可以指定 port 等配置
contentBase: './dist',
hot: true,
stats: 'errors-only',
},
// 該參數見下圖
devtool: 'cheap-source-map',
};
module.exports = merge(baseConfig, devConfig);
- webpack.prod.js
webpack 4.0 以上將 uglifyjs 與 treeshaking 設為 webpack 默認,只要設置mode = production 就默認開啟
// css 壓縮插件
const cssnano = require('cssnano');
// merge webpack.dev.js 與 webpack.prod.js
const merge = require('webpack-merge');
// 用於 cdn 加速 react,引用外部資源
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
// 提取 css 到單獨文件並且壓縮 css
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
// 前面提到的基本配置
const baseConfig = require('./webpack.base');
const prodConfig = {
mode: 'production',
plugins: [
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: cssnano,
}),
new HtmlWebpackExternalsPlugin({
externals: [
{
module: 'react',
entry: 'https://11.url.cn/now/lib/16.2.0/react.min.js',
global: 'React',
},
{
module: 'react-dom',
entry: 'https://11.url.cn/now/lib/16.2.0/react-dom.min.js',
global: 'ReactDOM',
},
],
}),
],
// code split
optimization: {
splitChunks: {
minSize: 0,
cacheGroups: {
commons: {
name: 'vendors',
chunks: 'all',
minChunks: 2,
},
},
},
},
};
module.exports = merge(baseConfig, prodConfig);
所需依賴
autoprefixer
babel-loader
clean-webpack-plugin
css-loader
cssnano
eslint-loader
file-loader
friendly-errors-webpack-plugin
glob
html-inline-css-webpack-plugin
html-loader
html-webpack-externals-plugin
html-webpack-inline-source-plugin
html-webpack-plugin
less
less-loader
mini-css-extract-plugin
node-notifier
optimize-css-assets-webpack-plugin
postcss-loader
postcss-preset-env
px2rem-loader
raw-loader
react
react-dom
style-loader
uglifyjs-webpack-plugin
url-loader
webpack
webpack-cli
webpack-merge
執行命令
在項目根目錄下的 package.json 的 scripts 里新增腳本:
開發環境 && 生產環境
"dev": "webpack-dev-server --config webpack.dev.js --open",
"build": "webpack --config webpack.prod.js",