// 创建项目目录
mkdir webpack-demo
// 进入该项目目录
cd webpack-demo
// 初始化项目
npm init
{
"name": "webpack4.0",
"version": "1.0.0",
"description": "",
"private": true, // 表示是私有项目,不会发布到 npm 线上仓库
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "lgk",
"license": "ISC" // 如果想开源,可以改为 MIT
}
// 全局安装 Webpack (不推荐)
// 如果两个项目都要 webpack 打包,且两个项目的版本不一样,就会导致有一个运行不起来
npm install webpack webpack-cli -g
// 查看版本
webpack --version
// 卸载 webpack webpack-cli
npm uninstall webpack webpack-cli -g
// 局部安装 Webpack
npm install webpack webpack-cli --save-dev
npm install webpack webpack-cli -D
// 查看版本
npx webpack -v
// 不知道一个包的某个版本是否存在
npm info webpack
const path = require('path');
module.exports = {
mode: 'production', // 如果不配置,默认就是 production
// entry: './src/index.js', // 入口文件:项目从哪个文件开始打包
entry: {
main: './src/index.js'
},
output: {
filename: 'bundle.js', // 打包生成的文件名
// path 路径必须为绝对路径
path: path.resolve(__dirname, 'dist')
}
}
{
"name": "webpack4.0",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"bundle": "webpack"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack-cli": "^4.8.0"
},
"dependencies": {
"webpack": "^5.54.0"
}
}
webpack 入口文件
npx webpack 入口文件
npm run bundle
npm install vue-loader --save-dev
const path = require('path');
module.exports = {
mode: 'production', // 如果不配置,默认就是 production
// entry: './src/index.js', // 入口文件:项目从哪个文件开始打包
entry: {
main: './src/index.js'
},
output: {
filename: 'bundle.js', // 打包生成的文件名
// path 路径必须为绝对路径
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.vue$/,
use: [{
loader: 'vue-loader',
options: {},
}]
},
]
}
}
// file-loader
npm install file-loader --save-dev
// url-loader
npm install url-loader --save-dev
const path = require('path');
module.exports = {
module: {
rules: [{
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'file-loader',
options: {
outputPath: 'images/', // 打包到 dist/images 下
name: '[name].[ext]',
},
}]
},
{
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
limit: 10240
},
}]
},
]
}
}
// style-loader
npm install style-loader --save-dev
// css-loader
npm install css-loader --save-dev
// sass-loader
npm install sass-loader --save-dev
// postcss-loader
npm install post-loader --save-dev
const path = require('path');
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
use: [{
loader: 'style-loader',
options: {},
},
{
loader: 'css-loader',
options: {
// 表示该loader引入之前还有引入两个loader
importLoaders: 2,
modules: true // css 模块化
}
},
{
loader: 'sass-loader',
options: {}
},
{
loader: 'postcss-loader', // 添加厂商前缀
options: {}
}]
}]
}
}
npm install autoprefixer --save-dev
module.exports = {
plugins: [
require('autoprefixer')
]
}
const path = require('path');
module.exports = {
module: {
rules: [{
test: /\.(eot|ttf|svg)$/,
use: [{
loader: 'file-loader',
options: {},
}]
},
]
}
}
npm install html-webpack-plugin --save-dev
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'production', // 如果不配置,默认就是 production
// entry: './src/index.js', // 入口文件:项目从哪个文件开始打包
entry: {
main: './src/index.js'
},
output: {
filename: 'bundle.js', // 打包生成的文件名
filename: '[name].js', // 多入口时
// path 路径必须为绝对路径
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.vue$/,
use: [{
loader: 'vue-loader',
options: {},
}]
},
]
},
plugins: [new HtmlWebpackPlugin({
template: 'src/index.html'
})]
}
npm install clean-webpack-plugin --save-dev
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
mode: 'production', // 如果不配置,默认就是 production
// entry: './src/index.js', // 入口文件:项目从哪个文件开始打包
entry: {
main: './src/index.js'
},
output: {
filename: 'bundle.js', // 打包生成的文件名
// path 路径必须为绝对路径
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.vue$/,
use: [{
loader: 'vue-loader',
options: {},
}]
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new HtmlWebpackPlugin(['dist'])
]
}
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
mode: 'production', // 如果不配置,默认就是 production
// entry: './src/index.js', // 入口文件:项目从哪个文件开始打包
entry: { // 多入口
main: './src/index.js',
sub: './src/index.js'
},
output: {
// publicPath: ‘’, // 会在 html 引入打包 js 文件前加该地址
// filename: 'bundle.js', // 单入口时打包生成的文件名
filename: '[name].js', // 多入口时的出口文件名与入口指定的相同
// path 路径必须为绝对路径
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.vue$/,
use: [{
loader: 'vue-loader',
options: {},
}]
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new HtmlWebpackPlugin(['dist'])
]
}
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
mode: 'production', // 如果不配置,默认就是 production
// entry: './src/index.js', // 入口文件:项目从哪个文件开始打包
// development devtool: 'cheap-module-eval-source-map',
// production devtool: 'cheap-module-source-map',
entry: { // 多入口
main: './src/index.js',
sub: './src/index.js'
},
output: {
// publicPath: ‘’, // 会在 html 引入打包 js 文件前加该地址
// filename: 'bundle.js', // 单入口时打包生成的文件名
filename: '[name].js', // 多入口时的出口文件名与入口指定的相同
// path 路径必须为绝对路径
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.vue$/,
use: [{
loader: 'vue-loader',
options: {},
}]
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new HtmlWebpackPlugin(['dist'])
]
}
npm install webapck-dev-server --save-dev
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
mode: 'production', // 如果不配置,默认就是 production
// entry: './src/index.js', // 入口文件:项目从哪个文件开始打包
// development devtool: 'cheap-module-eval-source-map',
// production devtool: 'cheap-module-source-map',
entry: { // 多入口
main: './src/index.js',
sub: './src/index.js'
},
devServer: {
contentBase: './dist', // 服务器建在哪个目录下
open: true, // 表示在启动 webpack-dev-server 时,会自动打开浏览器,然后自动访问服务器的地址
// proxy: { // 跨域:当用户访问 localhost:8080/api 时,会自动转发到 localhost:3000 的地址
// '/api': 'http://localhost:3000'
// },
// port: 9000, // 默认是 8080 端口,如果要改的话可以自行设置
},
output: {
// publicPath: ‘’, // 会在 html 引入打包 js 文件前加该地址
// filename: 'bundle.js', // 单入口时打包生成的文件名
filename: '[name].js', // 多入口时的出口文件名与入口指定的相同
// path 路径必须为绝对路径
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.vue$/,
use: [{
loader: 'vue-loader',
options: {},
}]
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new HtmlWebpackPlugin(['dist'])
]
}
{
"name": "webpack4.0",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"bundle": "webpack",
"watch": "webpack --watch", // 当源代码发生变化,webpack 就能监听到打包文件发生变化,然后就会重新打包
"start": "webpack-dev-server"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.54.0",
"webpack-cli": "^4.8.0"
}
}
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack')
module.exports = {
mode: 'development', // 如果不配置,默认就是 production
devtool: 'cheap-module-eval-source-map',
entry: { // 多入口
main: './src/index.js',
sub: './src/index.js'
},
devServer: {
contentBase: './dist', // 服务器建在哪个目录下
open: true, // 表示在启动 webpack-dev-server 时,会自动打开浏览器,然后自动访问服务器的地址
// proxy: { // 跨域:当用户访问 localhost:8080/api 时,会自动转发到 localhost:3000 的地址
// '/api': 'http://localhost:3000'
// },
// port: 9000, // 默认是 8080 端口,如果要改的话可以自行设置
hot: true, // 表示让 webpack-dev-server 开启 热更新
hotOnly: true // 表示即使 HMR 的功能没有生效,也会让浏览器自动的重新刷新
},
output: {
// publicPath: ‘’, // 会在 html 引入打包 js 文件前加该地址
// filename: 'bundle.js', // 单入口时打包生成的文件名
filename: '[name].js', // 多入口时的出口文件名与入口指定的相同
// path 路径必须为绝对路径
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.vue$/,
use: [{
loader: 'vue-loader',
options: {},
}]
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new HtmlWebpackPlugin(['dist']),
new webpack.HotModuleReplacementPlugin()
]
}
// 例如:监测 number.js 模块的更新
if(module.hot) {
module.hot.accept('./number', () => {
// 监测到 number.js 中代码发生改变后处理的业务
})
}
// babel-loader 只是将 webpack 和 Babel 打通,实际上 babel-loader 并不会将 ES6 转为 ES5
npm install --save-dev babel-loader @babel/core
// 所以还需要借助其他模块做语法转换
npm install --save-dev @babel/preset-env
// 对于一些ES6 新增的像 map 等函数,preset-env 还是不够,所以需要补充
npm install --save @babel/polyfill
// 安装好 polyfill 之后只需要在所有需要转换的代码之前引入即可
// import "@babel/polyfill"
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack')
module.exports = {
mode: 'development', // 如果不配置,默认就是 production
devtool: 'cheap-module-eval-source-map',
entry: { // 多入口
main: './src/index.js',
sub: './src/index.js'
},
devServer: {
contentBase: './dist', // 服务器建在哪个目录下
open: true, // 表示在启动 webpack-dev-server 时,会自动打开浏览器,然后自动访问服务器的地址
},
output: {
// publicPath: ‘’, // 会在 html 引入打包 js 文件前加该地址
// filename: 'bundle.js', // 单入口时打包生成的文件名
filename: '[name].js', // 多入口时的出口文件名与入口指定的相同
// path 路径必须为绝对路径
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.vue$/,
use: [{
loader: 'vue-loader',
options: {},
}]
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: [["@babel/preset-env", {
useBuiltIns: 'usage', // 按需打包 polyfill
targets: {
chrome: "67" // 对于已经支持ES6的浏览器,就不会转为ES5了
}
}]]
}
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new HtmlWebpackPlugin(['dist']),
new webpack.HotModuleReplacementPlugin()
]
}
{
presets: [
"@babel/preset-env", {
useBuiltIns: 'usage', // 按需打包 polyfill
targets: {
chrome: "67" // 对于已经支持ES6的浏览器,就不会转为ES5了
}
},
"@babel/preset-react"
]
}
module.exports = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: './dist',
open: true,
hot: true,
hotOnly: true,
},
entry: {
main: './src/index.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
module: {
// loader
rules: [{
test: /\.js$/,
exclude: /node_module/,
loader: 'babel-loader'
}]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
})
],
optimization: {
usedExports: true
}
}
{
"name": "test",
"sideEffects": false,
// "sideEffects": ["*.css"]
"version": "1.0.0",
//等等
}
webpack.dev.js 文件:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack')
module.exports = {
mode: 'development', // 如果不配置,默认就是 production
devtool: 'cheap-module-eval-source-map',
entry: { // 多入口
main: './src/index.js'
},
devServer: {
contentBase: './dist', // 服务器建在哪个目录下
open: true, // 表示在启动 webpack-dev-server 时,会自动打开浏览器,然后自动访问服务器的地址
port: 8080,
hot: true,
hotOnly: true
},
output: {
// publicPath: ‘’, // 会在 html 引入打包 js 文件前加该地址
// filename: 'bundle.js', // 单入口时打包生成的文件名
filename: '[name].js', // 多入口时的出口文件名与入口指定的相同
// path 路径必须为绝对路径
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.(eot|ttf|svg)$/,
use: [{
loader: 'file-loader',
options: {
outputPath: 'images/', // 打包到 dist/images 下
name: '[name].[ext]',
},
}]
},
{
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
limit: 10240
},
}]
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
},
{
test: /\.scss$/,
use: [{
loader: 'style-loader',
options: {},
},
{
loader: 'css-loader',
options: {
// 表示该loader引入之前还有引入两个loader
importLoaders: 2,
modules: true // css 模块化
}
},
{
loader: 'sass-loader',
options: {}
},
{
loader: 'postcss-loader', // 添加厂商前缀
options: {}
}]
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {}
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new HtmlWebpackPlugin(['dist']),
new webpack.HotModuleReplacementPlugin()
],
optimization: {
usedExports: true
}
}
webpack.prod.js 文件:
- 生产环境不需要 devServer
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
mode: 'production', // 如果不配置,默认就是 production
devtool: 'cheap-module-source-map',
entry: { // 多入口
main: './src/index.js'
},
output: {
// publicPath: ‘’, // 会在 html 引入打包 js 文件前加该地址
// filename: 'bundle.js', // 单入口时打包生成的文件名
filename: '[name].js', // 多入口时的出口文件名与入口指定的相同
// path 路径必须为绝对路径
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.(eot|ttf|svg)$/,
use: [{
loader: 'file-loader',
options: {
outputPath: 'images/', // 打包到 dist/images 下
name: '[name].[ext]',
},
}]
},
{
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
limit: 10240
},
}]
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
},
{
test: /\.scss$/,
use: [{
loader: 'style-loader',
options: {},
},
{
loader: 'css-loader',
options: {
// 表示该loader引入之前还有引入两个loader
importLoaders: 2,
modules: true // css 模块化
}
},
{
loader: 'sass-loader',
options: {}
},
{
loader: 'postcss-loader', // 添加厂商前缀
options: {}
}]
},
{
test: /\.vue$/,
use: [{
loader: 'vue-loader',
options: {},
}]
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {}
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new HtmlWebpackPlugin(['dist'])
]
}
package.json 文件:
{
"name": "webpack4.0",
"sideEffects": false,
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server --config webpack.dev.js",
"build": "webpack --config webpack.prod.js",
"test": "webpack --config webpack.dev.js"
},
"author": "",
"license": "ISC",
"devDependencies": {
},
"dependencies": {
}
}
抽取公共配置 webpack.common.js 文件:
- 合并配置文件需要安装第三方模块
npm install webpack-merge --save-dev
const webpack = require('webpack');
const merge = require('webapck-merge');
const commonConfig = require('./webpack.common.js');
const devConfig = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: './dist', // 服务器所在目录
open: true, // 开启服务
port: 8080, // 设置端口
hot: true, // 开启热更新
// hotOnly: true // 开启后编译出错不会自动刷新
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
}
module.exports = merge(commonConfig, devConfig)
const merge = require('webapck-merge');
const commonConfig = require('./webpack.common.js');
const prodConfig = {
mode: 'production',
devtool: 'cheap-module-source-map'
}
module.exports = merge(commonConfig, prodConfig)
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: { // 多入口
main: './src/index.js'
},
output: {
// path 路径必须为绝对路径
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.(eot|ttf|svg)$/,
use: [{
loader: 'file-loader',
options: {
outputPath: 'images/', // 打包到 dist/images 下
name: '[name].[ext]',
},
}]
},
{
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
limit: 10240
},
}]
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
},
{
test: /\.scss$/,
use: [{
loader: 'style-loader',
options: {},
},
{
loader: 'css-loader',
options: {
// 表示该loader引入之前还有引入两个loader
importLoaders: 2,
modules: true // css 模块化
}
},
{
loader: 'sass-loader',
options: {}
},
{
loader: 'postcss-loader', // 添加厂商前缀
options: {}
}]
},
{
test: /\.vue$/,
use: [{
loader: 'vue-loader',
options: {},
}]
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {}
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new HtmlWebpackPlugin(['dist'])
],
optimization: {
useExports: true
}
}
npm install lodash --save
// 引入lodash: import _ from 'lodash';
不进行代码分割存在的问题:
- 当引入第三方库和业务逻辑代码放在一起打包时,打包文件会很大,加载时间会很长
- 当每次业务逻辑发生变化时,又要重新加载这个体积很大的包,会耗时较长
普通解决方案:
- 可以把 lodash 等第三方库各自放在新建的 js 文件中引入,然后挂载在 window 对象上全局使用,同时在 entry 中配置入口指向该文件,这样就可以把第三方库与业务逻辑分开引入
// lodash.js 文件
import _ from 'lodash';
window._ = _;
entry: {
main: './src/index.js',
lodash: './src/lodash.js',
}
webpack 解决方案:
- Code Splitting 对代码进行拆分,可以让代码执行的性能更高
- Code Splitting 本质上和 webpack 没有关系,在没有 webpack 之前,可以像上面一样手动拆分代码
- 在 webpack4.0 提供 splitChunksPlugin 插件与 webpack 捆绑,不用安装就能使用进行代码分割
- webpack 中实现代码分割有两种方式:同步代码 和 异步代码
同步代码分割:
- webpack 自带 splitChunksPlugin 可以实现自动分割,只需要在 webpack.common.js 中做 optimization 的配置即可
optmization: {
splitChunksPlugins: {
chunks: 'all',
cacheGroups: {
vendors: false,
default: false
}
}
}
异步代码分割:
- 指的是使用 import() 引入的异步组件或模块代码
- 无需做任何配置,会自动进行异步代码分割,放置到新的文件中
- 在异步加载时可以使用魔法注释指定生成的异步文件名
// 例如 lodash 的引入时
function getComponent() {
return import(/* webpackChunkName: "lodash" */ 'lodash').then(({default: _}) => {
// lodash 使用逻辑
})
}
// 动态异步获取 若是不支持,可以安装如下插件
npm install @babel/plugin-syntax-dynamic-import --save-dev
// 然后在 .babelrc 文件中配置,然后 Babel 就能转以这种实验性质的语法
plugins: ["@babel/plugin-syntax-dynamic-import"]
splitChunksPlugin 配置参数:
- 如果将 splitChunks 设置为空对象,则会使用默认配置,如下
optimization: {
splitChunks: {
chunks: 'async', // all:对异步和同步都分割 async:只对异步分割
minSize: 30000, // 如果打包后包大于30000字节(30Kb)就会做代码分割
maxSize: 0, // 如果分割后还大于maxSize,会尝试再次进行分割(maxSize 一般不设置)
minChunks: 1, // 当一个模块至少使用 minChunk 次才会代码分割
maxAsyncRequests: 5, // 同时加载模块数最多是 5,如果超过就不分割
maxInitialRequests: 3, // 入口文件做分割,最多生成 3 个 js 文件,超过则不再分割
automaticNameDelimiter: '~', // 使用~作为下面的cacheGroups组名与文件名的连接符生成分割后的文件名
name: true, // 打包后的名字使用cacheGroups里的名字有效
cacheGroups: { // 打包同步代码时,若符合上面的条件则会到这,执行完成后才会进行分割
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10, // 值越大,这个组的优先级越高
filename: 'vendors.js'
},
default: {
minChunks: 2,
priority: -20, // -20 < -10,default 的优先级小于 vendors
reuseExistingChunk: true, // 如果一个模块被打包过了,再打包时就忽略该模块,直接使用
filename: common.js
}
}
}
}
output 中 filename 与 chunkFilename 的区别:
- filename 是入口文件对应生成的输出文件名
- chunkFilename 是入口文件间接引入生成的输出文件名
import(/* webpackPrefetch: true */ 'lodash')
npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const merge = require('webapck-merge');
const commonConfig = require('./webpack.common.js');
const prodConfig = {
mode: 'production',
devtool: 'cheap-module-source-map',
module: {
rules: [
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
'postcss-loader'
]
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[name].chunk.css'
})
]
}
module.exports = merge(commonConfig, prodConfig)
CSS 代码压缩:
- CSS 代码压缩可以使用 OptimizeCssAssetsPlugin 插件
npm install --save-dev optimize-css-assets-plugin
optimization: {
minimizer: [
new OptimizeCssAssetsPlugin({}) // 别忘了加空对象
]
}
// webpack.prod.js
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js'
}
optimization: {
runtimeChunk: {
name: 'runtime'
},
usedExports: true,
splitChunks: {
chunks: 'all'
}
}