Webpack一些配置介绍
安装
- 全局安装
webpack
和webpack-cli
,是为了可以使用webpack
这个命令,不然你使用不了命令,当然手动添加环境变量也是可以的,局部安装是为了锁定版本,方便开发统一版本号,这里是使用了指定版本号的,也是踩了坑的,版本号不同,配置大同小异,但是,里面一个变化,你不知道,出错了就有你好查的了。 本人在做开发的时候,遇到的最多的就是版本号的坑。基本上
webpack
版本号是多少,其他的关联包,基本都要在一定范围内,超出了范围,就等着一堆报错吧,本人用的这个版本是自己踩过确定可用的。npm i webpack@4.46 webpack-cli-3.3.12 -g npm i webpack@4.46 webpack-cli-3.3.12 -D
- 如果不想修改一次内容,就打包一次看效果,还可以安装下面和这个包
- 然后只需要运行,
npx webpack-dev-server
或者npx webpack serve
,然后我们再改动代码,就能立刻在浏览器中看到对应的效果了 npx webpack-dev-server
不好记还长,那么在package.json
的scripts中配置个dev启动命令吧:"dev": "webpack-dev-server"
或者"dev": "webpack serve"
该方式就是用来实时预览的,不会打包,只会在内存中虚拟打包,让你看到效果,需要打包的话还是要使用
webpack
命令打包。npm i webpack-dev-server@3.11.0
package.json文件中的配置
// 更新于2022/02/22
{
"name": "webpack1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server",
"build": "webpack --config webpack.config.js",
"prod": "webpack --config webpack.prod.config.js"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/polyfill": "^7.11.5",
"@babel/preset-env": "^7.11.5",
"add-asset-html-webpack-plugin": "^5.0.1",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"core-js": "^3.21.1",
"css-loader": "^4.3.0",
"eslint": "^7.11.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-loader": "^4.0.2",
"eslint-plugin-import": "^2.25.4",
"file-loader": "^6.1.0",
"html-loader": "^1.3.2",
"html-webpack-plugin": "^4.5.0",
"less": "^4.1.2",
"less-loader": "^6.0.0",
"mini-css-extract-plugin": "^1.0.0",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss": "^8.1.1",
"postcss-loader": "^4.0.4",
"postcss-preset-env": "^7.4.1",
"style-loader": "^2.0.0",
"url-loader": "^4.1.0",
"webpack": "^4.46.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0"
},
"dependencies": {
"@babel/polyfill": "^7.11.5",
"core-js": "^3.21.1",
"jquery": "^3.6.0"
},
"browserslist": {
"development": [
">0.2%",
"not dead",
"not op_mini all"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
},
"eslintConfig": {
"extends": "airbnb-base",
"parser": "babel-eslint"
}
}
webpack.config.js配置
配置中的五个核心点
Entry(入口)
- Entry 指示 Webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图
Output(输出)
- Output 指示 Webpack 打包后资源的 bundles 输出到哪里去,以及如何命名
Module
- Module中的Loader 让 Webpack 能够去处理那些非JS文件(webpack本身只理解JS,还有JSON)
Plugins(插件)
- Plugins 可以用于执行范围更广的任务,插件的范围包括从打包优化和压缩,一直到重新定义环境中的变量等
Mode(模式)
Mode 指示 Webpack 使用相应模式的配置
- development
- production
配置文件详细代码
/*
webpack.config.js: webpack的配置文件
作用:指示webpack干哪些活,即当你运行webpack指令时,会加载里面的配置
所有构建工具都是基于NodeJS平台运行的, 所以模块化采用的都是commonjs
开发环境配置
*/
// 使用resolve用来拼接绝对路径的方法
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 webpack = require('webpack')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
// 设置nodejs环境变量
process.env.NODE_ENV = 'development'
/*
entry: 入口起点
1. string ---> './src/index.js'
- 单入口
- 打包形成一个chunk,输出一个bundle文件。
- 此时chunk的名称默认为main
2. array ---> ['./src/index.js','./src/index2.js']
- 多入口
- 所有入口文件最终只会形成一个chunk,输出出去只有一个bundle文件。
- 一般来讲,只有在HMR功能中让html的热更新生效:['./src/index.js','./src/index.html']
3. object ---> { index: './src/index.js', index2:'./src/index2.js'}
- 多入口
- 有几个入口文件就形成几个chunk,输出几个bundle文件,这个也是文件切割的一种形式
- 此时chunk的名称是key
- 特殊用法:可以用来把两个打包成一个
{
index: ['./src/index.js','./src/add.js',
index2:'./src/index2.js'
}
*/
module.exports = {
// webpack配置
// 入口
entry: ['./src/index.js','./src/index.html'],
// 输出
output: {
// 输出文件名
filename: 'js/[name].[hash:10].js',
// 输出路径
path: resolve(__dirname,'dist'),
// 所有资源引入的公共路径前缀:'./img/bg.png'
// publicPath: '/',
// 非入口chunk的名称
// chunkFilename: '',
// 整个库向外暴露的变量名,一般只有结合dll才使用
// library: '[name]',
// 变量名添加到哪个上
// libraryTarget: 'window'
// libraryTarget: 'browser'
},
// loader的配置
module: {
// 详细loader配置
rules: [
// JS的语法检查:eslint eslint-loader
// 除了要上面的两个,我们还需要下载个规则,规则的意思是按照上面规则检查js的错误
// airbnb: eslint-config-airbnb-base eslint-plugin-import
// 除此之外还要在package.json中配置 eslintConfig
{
test: /\.js$/,
// 需要注意的是我们只需要检查自己的源代码,第三方的库是不用检查的
exclude: /node_modules|css/,
// 只检查src文件夹下面的文件
// include: resolve(__dirname, 'src'),
// 优先执行,比如eslint和babel这里两个,eslint就要先执行,不然就非常容易报错
enforce: 'pre',
// 延后执行,不写是中间执行
// enforce: 'post',
loader: 'eslint-loader',
options: {
// 开启eslint自动修复eslint的错误
fix: true
}
},
{
// 以下loader只会匹配一个,避免每个文件都过了一遍loader,主要是生产环境的打包速度优化
// 注意:不能有两个配置处理同意类型文件,比如babel-loader和eslint-loader都要处理js,那样只会执行一个,所以把其中一个还直接放在rules中
oneOf: [
// css文件处理
{
// 正则匹配文件
test: /\.css$/,
// 指定需要使用的loader
// use数组中loader执行顺序是,从右到左,从下到上
// use里面可以是直接的字符串,也可以是对象,使用对象通常使我们要修改里面的配置
use: [
// 创建一个style标签,将js中的样式资源插入到进去,添加到head中生效
// 'style-loader',
// 和上面style-loader不同的是,使用插件,可以把css单独打包出来
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
// 将css文件,变成commonjs模块,加载到js中。里面的内容是样式字符串
'css-loader',
// css兼容性处理,需要用到postcss,需要下载postcss-loader和postcss-preset-env
{
loader: 'postcss-loader',
options: {
postcssOptions: {
ident: 'postcss',
plugins: () => {
require('postcss-preset-env')()
}
}
}
}
]
},
// less文件处理
{
// 正则匹配文件
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
'css-loader',
// css兼容性处理,需要用到postcss,需要下载postcss-loader和postcss-preset-env
{
loader: 'postcss-loader',
options: {
postcssOptions: {
ident: 'postcss',
plugins: () => {
require('postcss-preset-env')()
}
}
}
},
'less-loader'
]
},
// 图片处理
{
// 正则匹配文件
test: /\.(jpg|png|gif|jpeg)$/,
// 因为url-loader依赖于file-loader,所以要下载两个loader
loader: 'url-loader',
options: {
// 图片小于8kb,会被转换成base64,
// 优点:减少请求数量,减轻服务器压力
// 缺点:图片提及会更大,文件请求诉速度会更慢
limit: 8092,
// 手动设置图片的名字(可以不设置):name(图片原来的名字),hash(hash值,10代表去前10位),ext(图片原来的格式)
name: '[name].[hash:10].[ext]',
// 因为文件的引入是es6语法,但是webpack是遵循commonjs规则的,所以想要html文件中想要使用图片,必须把es6关掉。这是给下面的html中图片处理用的
esModule: false,
// 指定打包后文件输出位置
outputPath: 'assets/imgs'
}
},
// html中图片处理
{
// 正则匹配文件
test: /\.html$/,
loader: 'html-loader',
},
// 处理其他类型文件
{
// 排除css,js,html等文件,使用这个打包方式
exclude: /\.(html|js|css|less|png|jpg|jpeg|gif)/,
loader: 'file-loader',
options: {
name: '[name].[hash:10].[ext]',
outputPath: 'assets'
}
},
// JS的兼容处理,即ES6转ES5:babel-loader, @babel/core, @babel/preset-env
// @babel/preset-env只做基本语法的转换
// @babel/polyfill做全类型转换,但是有一点,我们只需要做部分的转换,全部引入,体积就会太大了
// 按需加载:使用core.js
{
test: /\.js$/,
exclude: /node_modules|css/,
loader: 'babel-loader',
options: {
// 预设:指示babel做怎么样的兼容处理
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// 指定core-js版本
corejs: {
version: 3
},
// 指定兼容性做到浏览器的那个版本
targets: {
chrome: '60',
firefox: '50',
ie: '9',
safari: '10',
edge: '15'
}
}
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
// 主要是避免多个js的情况下,只修改其中一个或一部分,导致所有的js都要再构建一次
cacheDirectory:true
}
}
]
},
]
},
// plugins的配置
plugins: [
// 处理html
// html-webpack-plugin
// 功能:默认会创建一个空的HTML文件,自动引入打包好的所有资源
new HtmlWebpackPlugin({
// 复制'./src/index.html' 文件到打包好的文件中,并引入所有资源
template: './src/index.html',
// 压缩html代码
// minify: {
// // 移除空格
// collapseWhitespace: true,
// // 移除注释
// removeComments: true
// }
}),
// css单独提出来
new MiniCssExtractPlugin({
// 使用contenthash,可以让css使用缓存,只有当css修改才会重新打包,而hash和chunkhash都不行,因为hash每次打包都不一样,而chunkhash不行是因为css是在js中引入的,所以每次也都是变化的
filename: 'css/built.[contenthash:10].css'
}),
// 压缩css
// new OptimizeCssAssetsWebpackPlugin()
// 告诉webpack哪些库不参与打包,同时使用时的名称也需要改变
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, 'dll/manifest.json')
}),
// 将某个文件打包输出出去,并在html中自动引入改文件(给dll功能使用的)
new AddAssetHtmlWebpackPlugin({
filepath: resolve(__dirname, 'dll/jquery.js')
})
],
// 模式
mode: 'development', // 开发模式
// mode: 'production', // 生产模式,该模式会自动压缩代码
// 开发服务器 devServer: 用来自动化的编译,打开浏览器,自动刷新浏览器
// 自会在内存中编译打包,不会有任何的输出
devServer: {
// 项目构建后路径
contentBase: resolve(__dirname, 'dist'),
// 是否在首次编译后自动打开浏览器
open: true,
// 启动gzip压缩
compress: true,
// 地址
host: '127.0.0.1',
// 端口好
port: 8527,
/*
开启HMR功能,HMR:hot module replace(热加载)
* css在hot: true默认开启HMR
* js默认没有开启HMR
- 入口JS文件不需要开启HMR,所以需要监听的是其他模块
- 其他JS文件的监听方式是在入口JS里面写一个监听代码
if(module.hot) {
// 方法会监听add.js文件,一旦发生变化,其他模块会重新打包构建
// 然后执行后面的回调函数
module.hot.accept('./asstes/js/add.js',function() {
add()
})
}
* html默认没有开启HMR,而且同时会导致html的热更新失效,恢复热更新需要修改entry --> entry: ['./src/index.js','./src/index.html'],但是还是没有HMR,html也不需要HMR,尤其是单页面只有一个index.html的情况下
- 额外说:热更新和热加载不一样:
- 热更新:文件内动改动后,整个页面刷新,不保留任何状态(比如输入过内容的Input表单),相当于webpack帮你摁了F5刷新
- 热加载:文件改动后,以最小的代价改变被改变的区域。尽可能保留改动文件前的状态(对input输入内容后,修改其他标签的代码)
*/
hot: true,
// 监视contentBase目录下的所有文件,一旦文件变化就会reload
watchContentBase: true,
// 监视文件的配置
watchOptions: {
// 忽略要监视的文件
ignored: /node_modules/
},
// 不要显示启动服务器日志信息
clientLogLevel: 'none',
// 除了一些基本的启动信息外,其他内容都不要显示
quiet: true,
// 如果出错了,不要全屏提示
overlay: false,
// 服务器代理:解决开发环境跨域问题
proxy: {
// 一旦devServer(8527)服务器接收到 /api/xxx 的请求,就会转发到另个服务器上(3000)
'/api': {
target: 'http://localhost:3000',
// 发送请求时,请求路径重写,将 /api/xxx --> /xxx (去掉了 /api)
pathRewrite: {
'^/api': ''
}
}
}
},
// 提供源代码到构建后代码映射技术
devtool: 'eval-source-map',
/*
文件分开打包的第二种形式
可以将node_modules中代码单独打包成一个chunk最终输出,入口文件单独一个chunk
上面的是单入口文件,该功能还会自动分析多入口chunk中,有没有公共的文件,如果有会打包成一个单独的chunk
*/
// optimization: {
// splitChunks: {
// chunks: 'all'
// }
// },
// 用来处理我们不需要自己打包,而是通过cdn引入的一些文件
// externals: {
// // 拒绝某个文件被打包
// jquery: 'jQuery'
// }
// 解析模块的规则
resolve: {
// 配置解析模块路径的别名,优点是简写路径,缺点是没有路径提示
alias: {
$css: resolve(__dirname, 'src/css')
},
// 配置省略文件路径的后缀名
// extensions: ['js','json','jsx'],
// 告诉webpack解析模块是去找哪个目录
modules: [resolve(__dirname,'../node_modules'),'node_modules']
}
}
/*
tree shaking: 必须在production模式下,另外一个条件是,需要使用ES6的模块化,在这两个条件满足的情况下,会自动去除无用代码,较少代码体积
PS: 有的版本的treeshaking有点问题,会把css当成无用代码干掉,这个时候需要在package.json中添加点配置
- "sideEffects": ["*.css","*.less"] 意思是避开css和less文件进行tree shaking
- "sideEffects": false 意思是所有文件都可以进行tree shaking
*/
/*
source-map: 提供源代码到构建后代码映射技术(如果构建后代码出错了,通过映射可以追踪源代码的错误)
source-map: 外部
- 错误代码准确信息 和 源代码的错误位置
inline-source-map: 内联
- 只生成一个内联source-map
- 错误代码准确信息 和 源代码的错误位置
hidden-source-map: 外部
- 错误代码的错误原因,但是没有提示错误位置
- 不追踪源代码的错误,只能提示到构建后代码的错误位置
eval-source-map: 内联
- 每一个文件都生成对应的source-map,都在eval
- 错误代码准确信息 和 源代码的错误位置
nosource-source-map: 外部
- 错误代码准确信息,但是没有人任何源代码信息
cheap-source-map: 外部
- 错误代码准确信息 和 源代码的错误位置
- 只能精确到行,但是不能精确到行的哪一块出错
cheap-module-source-map: 外部
- 错误代码准确信息 和 源代码的错误位置
- module会将loader的source-map加入
内联和外部的区别:
1.外部生成了文件,内联没有
2.内联构建速度更快
开发环境:速度快,调试友好
- 速度快(eval>inline>cheap>...)
+ eval-cheap-source-map 这个组合最快
+ eval-source-map
- 调试更友好
+ source-map
+ cheap-module-source-map
+ cheap-source-map
- 一般开发环境用 eval-source-map
生产环境:源代码要不要隐藏,调试要不要友好
- 内联会让体积变大,所以生产环境不要用内联
- nosource-source-map: 全部代码隐藏
- hidden-source-map: 只隐藏源代码,会提示构建后代码错误信息
- 一般生产环境用 source-map
*/
转载自:https://segmentfault.com/a/1190000041958769