Webpack 中 webpack.config.js 文件的一些常见配置和解释
cnpm install style-loader css-loader less less-loader url-loader file-loader html-loader postcss-loader postcss-preset-env eslint eslint-loader eslint-plugin-import eslint-config-airbnb-base babel-loader @babel/core @babel/preset-env @babel/polyfill core-js html-webpack-plugin workbox-webpack-plugin thread-loader add-asset-html-webpack-plugin -D
webpack.config.js 文件内容
/**
* webpack 配置文件, 指定其执行的工作
* entry
* output
* module
* loader 引入 ==> 使用
* plugins 引入 ==> 声明 ==> 使用
* mode
*/
// [cnpm i style-loader css-loader less less-loader url-loader file-loader html-loader postcss-loader postcss-preset-env eslint eslint-loader eslint-plugin-import eslint-config-airbnb-base babel-loader @babel/core @babel/preset-env @babel/polyfill core-js html-webpack-plugin workbox-webpack-plugin thread-loader add-asset-html-webpack-plugin -D]
// resolve 用于拼接绝对路径的方法
const {resolve} = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 提取 css 为单独文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 压缩 css 文件
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
// PWA
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
// 启动 browserslist 中开发环境 (设置 nodejs 环境变量)
process.env.NODE_ENV = "development";
// 复用 CSS loader
const commonCssLoader = [
// 创建 style 标签, 将 js 中的样式资源插入进行, 添加到 head 中生效
// 'style-loader',
// MiniCssExtractPlugin.loader 替代 style-loader 用于单独提取 css 样式, 而不是创建 style 标签
{
loader: MiniCssExtractPlugin.loader,
options: {}
},
// 将 css 文件变成 commonjs 模块加载 js 中, 里面内容是样式字符串
{
loader: 'css-loader'
},
// css 兼容性处理: postcss
// 使用 postcss 默认配置
// 'postcss-loader',
// 修改 postcss 默认配置 postcss.config.js
{
loader: "postcss-loader"
}
];
// 复用照片 options
const commonImgOptions = (prePath) => {
return {
// 图片大小小于 10kb 就会被 base64 处理 (优点: 减少请求数量)
limit: 10 * 1024,
// 关闭 url-loader 中 ES6 模块化, 使用 commonjs 解析
esModule: false,
// 给图片进行从命名 [hash:10]: 文件 hash 值的前十位, [ext]: 文件的原扩展名
name: prePath + '/[hash:10].[ext]',
// 打包输出路径
// outputPath: prePath,
// 统一设置公共路径
publicPath: '../'
}
}
// 插件提出来
const plugins = [
// new HtmlWebpackPlugin(): 建立一个空 HTML 文件, 自动打包所有输出的资源 (JS/CSS)
new HtmlWebpackPlugin({
// 建立指定的 HTML 文件
template: "./src/view/index.html",
// 对输出的 HTML 文件选择路径和自定义文件名
filename: 'webpack.html',
// 压缩 HTMl 代码
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true
}
}),
// 提取 css 为单独文件 [cnpm i mini-css-extract-plugin -D]
new MiniCssExtractPlugin({
// 对输出的 css 文件选择路径和自定义文件名
filename: 'css/webpack.[contenthash:10].css'
}),
// 压缩 css
new OptimizeCssAssetsWebpackPlugin(),
// PWA: 渐进式网络开发应用程序(离线可访问) workbox --> workbox-webpack-plugin
new WorkboxWebpackPlugin.GenerateSW({
// 1.帮助 serviceworker 快速启动 2.删除旧的 serviceworker
// 生成一个 serviceworker 配置文件~
clientsClaim: true,
skipWaiting: true
}),
// 告诉 webpack 哪些库不参与打包, 同时使用时的名称也得变~
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, "dll/manifest.json")
}),
// 将某个文件打包输出去, 并在 html 中自动引入该资源
new AddAssetHtmlWebpackPlugin({
filepath: resolve(__dirname, "dll/jquery.js")
})
];
module.exports = {
// 入口起点文件
entry: [
'./src/index.js',
'./src/view/index.html'
],
// 输出内容
output: {
// 输出文件名
// chunkhash: 根据 chunk 生成的 hash 值. 如果打包来源于同一个 chunk, 那么 hash 值就一样
// contenthash: 根据文件的内容生成 hash 值. 不同文件 hash 值一定不一样
filename: "js/webpack.[contenthash:10].js",
// 输出路径, __dirname: 当前文件路径的绝对路径
path: resolve(__dirname, 'build')
},
// loader 配置
module: {
// 不同的文件配置不同的资源
rules: [
{
// eslint 语法检查
test: /\.js$/,
// 只检查自己写的代码
exclude: /node_modules/,
// 优先执行
enforce: "pre",
// 以后执行
// enforce: "post",
loader: 'eslint-loader',
// 使用 airbnb 提供的 eslint 规则检查, 在 package.json 中设置 eslintConfig
options: {
// 自动修复 eslint 错误
fix: true
}
},
{
// 以下 loader 指挥执行一个, 不能有两项配置处理同一类文件
oneOf: [
{
// 匹配 css 文件
test: /\.css$/,
// 使用那些 loader 进行处理
use: [...commonCssLoader]
},
{
// 匹配 less 文件
test: /\.less$/,
// 使用那些 loader 进行处理
use: [
...commonCssLoader,
// 将 less 文件编译成 css 文件
'less-loader'
]
},
{
// 匹配照片文件
test: /\.(jpg|png|gif)$/,
// 使用那些 loader 进行处理
loader: 'url-loader',
// 打包条件
options: commonImgOptions('img')
},
{
// 匹配 icon 文件
test: /\.(icon|ttf|bin|eot|woff|woff2|svg)$/,
// 使用那些 loader 进行处理
loader: 'url-loader',
// 打包条件
options: commonImgOptions('icon')
},
{
// 匹配 HTML 中 img 标签文件
test: /\.html$/,
// 使用那些 loader 进行处理 (负责引入, 从而由 url-loader 处理)
loader: 'html-loader'
},
{
// 匹配其他资源
exclude: /\.(css|js|less|jpg|png|gif|icon|ttf|bin|eot|woff|woff2|svg|html|json)$/,
// 使用那些 loader 进行处理
loader: 'file-loader',
// 打包条件
options: {
// 进行从命名 [hash:10]: 文件 hash 值的前十位, [ext]: 文件的原扩展名
name: 'other/[hash:10].[ext]',
// 打包输出路径
// outputPath: 'other',
// 统一设置公共路径
publicPath: '../'
}
},
{
// 基础 JS 兼容性处理 babel-loader @babel/core @babel/preset-env
// 全面 JS 兼容性处理 @babel/polyfill
// 需要 JS 兼容性处理 core-js
test: /\.js$/,
// 排除第三方
exclude: /node_modules/,
use: [
/**
* 开启多进程打包 thread-loader
* 进程启动大概为 600ms, 进程通信也有开销, 只有工作消耗时间比较长, 才需要多进程打包
*/
{
loader: 'thread-loader',
options: {
// 进行为 2
workers: 2
}
},
{
loader: 'babel-loader',
// 预设: 指示 babel 做怎么样的兼容性处理
options: {
presets: [
[
"@babel/preset-env",
{
//按需加载
useBuiltIns: 'usage',
//指定 core-js 版本
corejs: {
version: 3
},
// 指定兼容性做到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
edge: '17',
safari: '10'
}
}
]
],
// 开启 babel 缓存
/**
* 缓存:
* babel缓存
* cacheDirectory : true文件资源缓存
* hash:每次 webpack 构建时会生成一个唯一的 hash 值. 问题: 因为 js 和 css 同时使用一个 hash 值.
* 如果重新打包, 会导致所有缓存失效. (可能我却只改动一个文件)
* chunkhash: 根据 chunk 生成的 hash 值. 如果打包来源于同一个 chunk, 那么 hash 值就一样
* contenthash: 根据文件的内容生成 hash 值. 不同文件 hash 值一定不一样
*/
cacheDirectory: true
}
}
]
}
]
}
]
},
// plugins 配置
plugins: plugins,
/**
* 代码分割
* 1. 可以将 node_modules 中代码单独打包一个 chunk 最终输出
* 2. 自动分析多入口 chunk 中, 有没有公共的文件. 如果有会打包成单独一个 chunk
*/
optimization: {
splitChunks: {
chunks: 'all'
}
},
// 模式 development: 开发模式, production: 生产模式. (生产模式下会自动压缩 JS 代码)
mode: "production",
// 忽略 npm 下载的包进行打包
externals: {
// 拒绝 JQuery 打包
jquery: "JQuery"
},
// 开发服务器 devServer: 用来自动化. (自动编译, 自动打开浏览器, 自动刷新浏览器~~) 只会在内存中编译打包, 没有任何输出.
// 启动指令: npx webpack-dev-server [cnpm i webpack-dev-server -D]
devServer: {
contentBase: resolve(__dirname, 'build'),
// 启动 gzip 压缩
compress: true,
// 端口号
port: 3000,
// 自动打开浏览器
open: true,
// HMR: hot module replacement 热模块替换 / 模块热替换 只能处理非入口文件
// 作用: 一个模块发生变化, 只会重新打包这一个模块 (而不是打包所有模块)
hot: true
// 不要显示启动服务器日志信息
// clientLogLevel: 'none',
// 除了一些基本启动信息以外, 其他内容都不要显示
// quiet: true,
// 如果出错了, 不要全屏提示~
// overlay: false
},
// source-map: 一种提供源代码到构建后代码映射技术 (如果构建后代码出错了, 通过映射可以追踪源代码错误)
/**
* [inline-|hidden-|eval-][nosources-][cheap-[module-]]
* source-map: 外联 [错误代码准确信息和源代码的错误位置]
* inline-source-map: 内联-只生成一个内联 [错误代码准确信息和源代码的错误位置]
* hidden-source-map: 外联 [错误代码错误原因, 但是没有错误位置, 不能追踪源代码错误, 只能提示到构建后代码的错误位置]
* eval-source-map: 内联-每个文件都生成一个内联 [错误代码准确信息和源代码的错误位置]
* nosources-source-map: 外联 [错误代码准确信息, 但是没有任何源代码信息]
* cheap-source-map: 外联 [错误代码准确信息, 源代码的错误位置, 只能精确的行]
* cheap-module-source-map: 外联 [module: 会将 loader 的 source map 加入]
* 开发环境: 速度快, 调试更友好 ===> eval-source-map
* 速度快 (eval > inline > cheap >...)
* 调试更友好 source-map > cheap-module-source-map
* 生产环境: 源代码要不要隐藏? 调试要不要更友好, 基本不用内联 ===> source-map
*/
devtool: 'eval-source-map'
}
/**
* tree shaking: 去除无用代码
* 前提: 1.必须使用 ES6 模块化 2.开启 production 环境作用: 减少代码体积
* 在 package.json 中配置
* "sideEffects": false 所有代码都没有副作用(都可以进行 tree shaking)
* 问题:可能会把 css/@babel/polyfill (副作用) 文件干掉
* "sideEffects": ["*.css", "*.less"]
*/
package.json 内容
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
},
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
},
"sideEffects": [
"*.css",
"*.less"
]
webpack.dll.js 内容
/**
* webpack --config webpack.dll.js
* cnpm i jquery
*/
const {resolve} = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
// 最终打包生成的 [name] --> jquery, ['jquery'] --> 要打包的库是 jquery
jquery: ['jquery']
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'dll'),
// 打包的库里面向外暴露出去的内容叫什么名字
library: '[name]_[hash]'
},
plugins: [
// 打包生成一个 manifest.json --> 提供和 jquery 映射
new webpack.DllPlugin({
// 映射库的暴露的内容名称
name: '[name]_[hash]',
// 输出文件路径
path: resolve(__dirname, 'dll/manifest.json')
})
]
};
postcss.config.js 内容
module.exports = {
plugins: [
require('postcss-preset-env')
]
}
index.js 内容
// 引入 JS 兼容
// import '@babel/polyfill'
/**
* 1.运行指令:
* 开发环境: webpack ./src/index.js -o ./build --mode=development
* webpack 会以 ./src/index.js 为入口文件开始打包,打包后输出到 ./build/main.js 整体打包环境,是开发环境
* 生产环境: webpack ./src/index.js -o ./build --mode=production
* webpack 会以 ./src/index.js 为入口文件开始打包,打包后输出到 ./build/main.js 整体打包环境,是生产环境
* 2. webpack 可以处理 js/json 不能处理 css/img 等资源
*/
import { library } from '@fortawesome/fontawesome-svg-core';
import { fas } from '@fortawesome/free-solid-svg-icons';
import { far } from '@fortawesome/free-regular-svg-icons';
import { fab } from '@fortawesome/free-brands-svg-icons';
import 'font-awesome/css/font-awesome.css';
import './css/style.css';
import './css/style_less.less';
import data from './data/data.json';
import print from './js/print';
library.add(fas, far, fab);
console.log(data);
function add(x, y) {
return x + y;
}
// eslint-disable-next-line
console.log(add(1, 2)); // 下一行 eslint 所有规则都失效 (下一行不进行 eslint 检查)
const a = function a() {
console.log(12);
};
console.log(a);
print();
// js 热加载
if (module.hot) {
// 监听到 HMR 就执行
module.hot.accept('./js/print.js', () => {
print();
});
}
/**
* 通过 js 代码, 让某个文件被单独打包成一个 chunk import 动态导入语法: 能将某个文件单独打包
* 懒加载~: 当文件需要使用时才加载~
* 预加载 prefetch: true 会在使用之前, 提前加载 js 文件 (等其他资源加载完毕, 浏览器空闲了, 再偷偷加载资源) 兼容性差, 慎用
*/
// import(/* webpackChunkName: 'test' */ "./js/test").then((result) => {
// // "文件加载成功~"
// // eslint-disable-next-line
// console.log(result);
// }).catch(() => {
// // eslint-disable-next-line
// console.log('文件加载失败~');
// });
// 注册 serviceworker
// 处理兼容性问题
/**
* 2. sw代码必须运行在服务器上
* -->nodejs
* -->
* cnpm i serve -g
* serve -s build 启动服务器, 将 build 目录下所有资源作为静态资源暴露出去
*/
/**
* "eslintConfig": {
* "extends": "airbnb-base",
* "env": {
* "browser": true
* }
* },
*/
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js').then(() => {
// eslint-disable-next-line
console.log('sw 注册成功了~');
}).catch(() => {
// eslint-disable-next-line
console.log('sw 注册失败了~');
});
});
} else {
// eslint-disable-next-line
console.log('sw 不兼容~');
}