Webpack5进阶

Webpack 4.0 指定环境 webpack --env.production
Webpack 5.0 指定环境 webpack --env production
module.exports = (env, argv) => {
   const config = {}
   if(env.production){
      config.mode = 'production'
      config.plugins = []
   }

  return config
}
npm i -D webpack-merge
// /config/webpack.dev.conf.js

const { merge } = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')

const devWebpackConfig = merge(baseWebpackConfig, {


})
module.exports = devWebpackConfig
webpack --config ./config/webpack.dev.conf.js
// package.json

"build:dev": "webpack --config config/webpack.dev.conf.js"
"build:prod": "webpack --config config/webpack.prod.conf.js"
"dev": "webpack serve --config config/webpack.dev.conf.js"
"start": "webpack serve --config config/webpack.prod.conf.js"
// DefinePlugin
可以自己定义一些全局变量
const webpack = require("webpack")

module.exports = {
   plugins: [
       new webpack.DefinePlugin({
           API_BASE_URL: JSON.stringify('https://api.example.com')
       })
   ]
}
钩子函数
environment  环境准备好  SyncHook
Compile 编译开始 SyncHook
Compilation 编译结束 SyncHook
emit 资源打包到output之前 AsyncSeriesHook
afterEmit 资源打包到output之后 AsyncSeriesHook
done 打包完成 SyncHook
下面是一个基本写法:
new EmitHook({target: '.css'}),
class EmitHook {
	constructor(options){
		console.log('插件选项:', options)
		this.userOptions = options || {}
	}

	apply(compiler){
		compiler.hooks.emit.tap('插件名称',(compilation) => {
			for(const name in compilation.assets){
				if(name.endsWith(this.userOptions.target)){
					const contents = compilation.assets[name].source()
					const noComments = contents.replace(/\/\*[\s\S]*?\*\//g,'')
					compilation.assets[name] = {
						source: () => noComments,
						size: () => noComments.length
					}
				}
			}

		})
	}
}


module.exports = EmitHook
自定义Loader
需要loader-utils加载配置项
npm i -D loader-utils
const marked = require('marked')
const { getOptions } = require('loader-utils')

module.exports = function (source) {
	// 获取loader配置项
	const options = getOptions(this)

	// 对输出内容进行处理
	const html = marked(source)

	return html
}
代码分离
多入口打包:配置entry 加载多个入口文件
提取公共模块:optimization.splitChunks.chunks: all
动态导入:按需加载|预加载
// 多入口打包
entry: {index: './src/main.js', about: './src/about.js'},
output: {
	path: path.resolve(__dirname,'dist'),
	filename: '[name].bundle.js',
	publicPath: '',
},
plugins: [
	new HtmlWebpackPlugin({
		filename: 'index.html',
		template: './index.ejs',
		title: '测试标题',
		// 指定要加载的打包文件
		chunks: ['index']
	}),
	new HtmlWebpackPlugin({
		filename: 'about.html',
		template: './about.ejs',
		title: '测试标题',
		chunks: ['about']
	}),
],
// 提取公共模块
optimization: {
   splitChunks: {
       chunks: all
   }
}
// 按需加载 预加载 使用魔法字符串
/* webpackChunkName: 'desc' webpackPrefetch: true */
// Source Map
devtool = 'source-map'
// 其他
webpack4  cheap-module-eval-source-map
webpack5  eval-cheap-module-source-map

// 命名格式
^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map$
摇树
// usedExports
optimization.usedExports
/* unused harmony export xxxx */
terser-webpack-plugin (w5不需要单独安装,w4需要单独安装)
optimization.usedExports:true
optimization.minimize:true //设置
optimization.mimimizer: [new TerserPlugin()]
TreeShaking与SourceMap存在兼容问题
devtool:source-map | inline-source-map | hidden-source-map | nosources-source-map // 只支持这几种
// sideEffects
// 如果函数中修改了全局变量那么是有副作用的
// sideEffets 将未使用的无副作用的函数干掉
optimization.sideEffects: true
缓存
babel缓存
bebel-loader 的 options 里 cacheDirectory: true
[hash] 全变 [chunkhash] 影响一路 [contenthash] 影响某文件
resolve 模块解析
resolve
alias: 配置模块加载路径别名 alias:{'@': resolve('src')}
extensions: 引入模块时,可省略哪些后缀 extensions: ['js', 'json'] // 同时代表顺序
需要指定模块默认加载路径
modules: [resolve(__dirname, './node_modules'),'node_modules']
externals: 排除打包依赖项
externals: {
'jquery': 'jQuery'
}