webpack.config.js
/* 未使用脚手架打包
//开发环境
webpack '输入文件' -o '输出文件' --mode=development
//生产环境
webpack '输入文件' -o '输出文件' --mode=production
*/
const { resolve } = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')
const webpack = require('webpack')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
/*
## 懒加载
## import动态导入能将导入的文件单独打包,跟多入口文件效果类似
webpackChunkName: 'test'
import('./test')
.then(res => {
// 成功引入后执行的步骤
})
.catch(err => {
console.log('文件加载失败~')
})
*/
// ## 预加载
// import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then()
// ## 懒加载
// import(/* webpackChunkName: 'test' */'./test').then()
module.exports = {
// 单入口打包(打包成一个chunk)
entry: './src/index.js',
/*
另外的写法:
// 单文件入口(打包成一个chunk),add.js加到index.js上,仅用于HMR HTML文件热更新
entry: ['./src.index.js', './src/add.js'],
// 多入口打包(打包成多个chunk,也可以进行代码分割)
entry: {
index: './src.index.js',
add: './src/add.js'
},
// 多入口加文件合并(打包成多个chunk)
entry: {
index: ['./src.index.js', './src/count.js'],
add: './src/add.js'
},
*/
output: {
// 文件名称(指定名称+目录)
/*
## hash 每次打包都会生成一个唯一的hash值
## chunkhash: 根据输出的不同的chunk生成不同的chunk值,
## contenthash: 根据 不同的文件生成不同的hash值(推荐)
*/
filename: 'js/[name].[contenthash: 8].js',
// 输出所有文件的公共目录
path: resolve(__dirname, 'build'),
// 所有资源的引入公共路径前缀,相当于跨域中的前缀
publicPath: '/',
// 非入口chunk的名称,不设置都会走filename的方式命名,例如import('../xxx.js')导入的文件
chunkFilename: '[name]_chunk.js',
// 打包后要引用其中的文件,通过library暴露一个对象,达到调用的目的,一般结合dll使用
library: '[name]',
// 暴露的对象名添加到哪个地方去,window/global/commomjs
libraryTarget: 'window'
},
module: {
rules: [
/* 检查js文件格式 */
{
// 在package.json中配置eslintConfig
test: /\.js$/,
include: resolve(__dirname, 'src'),
exclude: /node_modules/,
// 多个loader
loader: 'eslint-loader',
// 优先执行
enforce: 'pre',
// 具体的配置选项
options: {
// 自动修复
fix: true,
// 指定错误报告的格式规范
formatter: require('eslint-friendly-formatter')
}
},
/* 处理HTML文件中引入的图片 */
{
test: /\.html$/,
include: resolve(__dirname, 'src'),
exclude: /node_modules/,
loader: 'html-withimg-loader',
},
/* 打包图片和其他资源 */
{
exclude: /\.(css|html|js|json)$/,
loader: 'file-loader',
options: {
name: '[hash: 10].[ext]',
outputPath: 'static/media/'
}
},
{
// 以下配置对每个检查的文件只会生效一个
oneOf: [
/* 打包图片资源 */
{
test: /\.(jpg|png|gif|bmp|jpeg)$/,
include: resolve(__dirname, 'src'),
exclude: /node_modules/,
loader: 'url-loader',
options: {
// 图片大小限制,小于8kb使用base64处理
limit: 8 * 1024,
// 关闭url-loader es6模块化,使用commonJs解析
esModule: false,
// 图片重命名
name: '[hash: 10].[ext]',
// 指定打包输出路径
outputPath: 'static/imgs/'
}
},
/* 打包css资源 */
{
test: /\.css$/,
// 指定检查的文件路径
include: resolve(__dirname, 'src'),
// 排除不需要检查的文件路径
exclude: /node_modules/,
// 多个loader
use: [
MiniCssExtractPlugin.loader,
'css-loader',
// css兼容性处理,配合package.json中的browswerlist使用
{
loader: 'postcss-loader',
options: {
execute: true,
postcssOptions: {
plugins: [
[
'postcss-preset-env'
]
]
}
}
}
]
},
{
test: /\.less$/,
// 指定检查的文件路径
include: resolve(__dirname, 'src'),
// 排除不需要检查的文件路径
exclude: /node_modules/,
// 多个loader
use: [
MiniCssExtractPlugin.loader,
'css-loader',
// css兼容性处理
{
loader: 'postcss-loader',
options: {
execute: true,
postcssOptions: {
plugins: [
[
'postcss-preset-env'
]
]
}
}
},
'less-loader'
]
},
{
test: /\.scss$/,
// 指定检查的文件路径
include: resolve(__dirname, 'src'),
// 排除不需要检查的文件路径
exclude: /node_modules/,
// 多个loader
use: [
MiniCssExtractPlugin.loader,
'css-loader',
// css兼容性处理
{
loader: 'postcss-loader',
options: {
execute: true,
postcssOptions: {
plugins: [
[
'postcss-preset-env'
]
]
}
}
},
'sass-loader'
]
},
/* js兼容性处理 */
{
test: /\.js$/,
include: resolve(__dirname, 'src'),
exclude: /node_modules/,
use: [
/*
开启多进程打包
多进程需启动(约600ms),只有打包时间长的时候适用
{
loader: 'thread-loader',
options: {
workers: 2 //开启进程2个
}
}
*/
'thread-loader',
{
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: "usage", // or "entry"
// 指定core-js版本
corejs: {
version: 3
},
// 指定兼容到哪个版本的浏览器
targets: {
chrome: '90',
firefox: '60',
ie: '9'
}
}
]
],
// 开启babel缓存
cacheDirectory: true
}
}
]
}
]
}
]
},
plugins: [
/* 创建并复制index.html文件 */
new HtmlWebpackPlugin({
// 引入项目的根HTML文件
template: './src/index.html',
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true
}
}),
/* 抽离css成单独文件 */
new MiniCssExtractPlugin({
filename: 'css/[contenthash: 10].css'
}),
/* 压缩css文件 */
new OptimizeCssAssetsWebpackPlugin(),
/* 告诉webpack,根据mainfest映射,哪些库不用再打包 */
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, 'dll/mainfest.json')
}),
// 配合dll, 引入dll中已经压缩的库
new AddAssetHtmlWebpackPlugin({
filepath: resolve(__dirname, 'dll/jquery.js')
})
],
// 解析模块的规则
resolve: {
// 配置解析模块的路径别名,例如 src别名是@
alias: {
$css: resolve(__dirname, 'src/css'),
$assets: resolve(__dirname, 'src/assets')
},
// 配置省略文件路径的后缀名,文件引入可以省略后缀名
extensions: ['.js', '.json'],
// 告诉 webpack 解析模块是去找哪个目录,不配置默认会逐层向上找
modules: [resolve(__dirname, './node_modules'), 'node_modules']
},
devServer: {
// 运行代码的目录
contentBase: resolve(__dirname, 'build'),
// 监视contentBase目录下的所有文件,一旦文件变化就会reload
watchContentBase: true,
// 监视配置
watchOptions: {
// 忽略文件
ignored: /node_modules/
},
// 启动gzip压缩
compress: true,
// 端口号
port: 8888,
// 指定域名
host: 'localhost',
// 自动打开浏览器
open: true,
// 开启HMR功能
hot: true,
// 不显示启动服务日志信息
clientLogLevel: 'none',
// 除基本启动信息,其他内容不显示
quiet: true,
// 如果出错不要全屏提示
overlay: false,
// 服务器代理 --> 解决开发环境下跨域问题,与vue相似
proxy: {
// 一旦遇到/api,就转到target这个路径下,并且路径重写,去掉/api
'/api': {
target: 'http://localhost:8080',
// 路径重写
pathRewrite: {
'^/api': ''
}
}
}
},
// 将node_modules中的代码单独打包成一个chunk输出,单/多入口都适用
optimization: {
/* 代码分割 */
splitChunks: {
chunks: 'all',
// 分割的chunk最小为30kb
minSize: 30 * 1024,
// 无最大限制
maxSize: 0,
// 要提取的chunks最少被引用1次
minChunks: 1,
// 按需加载时并行加载的文件的最大数量
maxAsyncRequests: 5,
// 入口js文件最大并行请求数量
maxInitialRequests: 3,
// 名称连接符
automaticNameDelimiter: '~',
// 可以使用命名规则
name: true,
// 分割chunk的组
cacheGroups: {
// node_modules文件会被打包到vendors组的chunk中 --> vendors~xxx.js
// 满足上边的公共规则
vendors: {
test: /[\\/]node_modules[\\/]/,
// 优先级
priority: -10
},
default: {
minChunks: 2,
priority: -20,
// 如果当前要打包的模块,和之前已经提取的模块是同一个,就不在重新打包
reuseExistingChunk: true
}
}
},
// 将当前模块记录其他模块的hash值单独打包成一个文件,
// 解决被引用文件修改,hash值改变,引用文件跟着重新打包的问题(缓存失效)
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`
},
// 配置生产环境的压缩方案: js和css
minimizer: [
new TerserWebpackPlugin({
// 开启缓存
cache: true,
// 开启多进程打包
parallel: true,
// 启动source-map
sourceMap: true
})
]
},
devtool: source-map,
externals: {
// 忽略库名 -- 忽略包名
jquery: 'jQuery' // 忽略打包jQuery
},
// 指定模式: 开发/生产(production)
/*
## tree shaking:去除无用代码
## 前提: 1. 必须使用ES6模块化 2.开启production环境
## package.json中配置"sideEffects": ["*.css","*.less"] -->不将设置的文件类型tree shaking
*/
mode: 'development'
}
webpack.dll.js
const { resolve } = require("path");
const webpack = require('webpack')
/*
使用dll技术对某些第三方库进行单独打包
webpack --config webpack.dll.js
*/
module.exports = {
entry: {
// 最终打包生成的[name] -->jquery
// ['jquery'] --> 要打包的库是jQuery
jquery: ['jquery']
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'dll'),
library: '[name]_[hash: 8]'
},
plugins: [
// 打包生成一个mainfest.json文件 ,提供与要打包文件的映射关系
new webpack.DllPlugin({
name: '[name]_[hash]', // 映射库的暴露的内容名称
path: resolve(__dirname, 'dll/mainfest.json') // 输出文件路径
})
]
}