webpack其实是一个静态模块打包工具css
webpack 处理项目时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序须要的每一个模块,而后将全部这些模块打包成一个或多个 bundle。html
npm run dev
npm run build
复制代码
...
"scripts": {
"dev_def": "webpack-dev-server --inline --public --config build/dev.js",
"dev": "nodemon --watch config/index.js --exec \"webpack-dev-server --inline --public --config build/dev.js\"",
"start": "npm run dev",
"build": "cross-env NODE_ENV=production node build/build.js"
}
...
复制代码
是一个轻量级的服务器,修改文件源码后,自动刷新页面将修改同步到页面上vue
webpack-dev-server --inline --public --config build/dev.js
复制代码
module.exports = {
//...
devServer: {
inline: true
}
};
复制代码
会监测项目中的文件,一旦发现文件有改动,Nodemon 会自动重启应用node
nodemon --watch config/index.js --exec \"webpack-dev-server --inline --public --config build/dev.js\" 复制代码
这句话的意思就是: 用nodemon监控config/index.js文件,若是有变化,则从新执行【webpack-dev-server --inline --public --config build/dev.js】的命令linux
而【webpack-dev-server --inline --public --config build/dev.js】命令对项目自己具备热更新功能,但webpack配置文件修改时,dev-sever自己不会生效。而用nodemon就是在webpack配置文件修改时也重启服务,算是一个自动补充webpack
解决跨平台设置和使用环境变量的脚本,如变量名称、路径方面的抹平es6
module.exports = {
// 入口文件
entry: {
app: './src/js/index.js'
},
// 在哪里输出它所建立的 bundles
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/' //确保文件资源可以在 http://localhost:3000 下正确访问
},
// 开发者工具 source-map
devtool: 'inline-source-map',
// 建立开发者服务器
devServer: {
contentBase: './dist',
hot: true // 热更新
},
plugins: [
// 删除dist目录
new CleanWebpackPlugin(['dist']),
// 从新穿件html文件
new HtmlWebpackPlugin({
title: 'Output Management'
}),
// 以便更容易查看要修补(patch)的依赖
new webpack.NamedModulesPlugin(),
// 热更新模块
new webpack.HotModuleReplacementPlugin()
],
// 环境
mode: "development",
// loader配置
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
}
}
复制代码
__dirname: 当前文件所在文件夹的绝对路径web
entry: './path/to/my/entry/file.js'
// 或者(对象写法)
entry: {
main: './path/to/my/entry/file.js'
}
复制代码
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
复制代码
entry:{
vendor:[resolve('src/lib/polyfill.js'), 'vue', 'vue-router'], // 不推荐
app: resolve('src/main.ts')
}
复制代码
在webpack4以前的版本中,一般将供应商添加为单独的入口点,以将其编译为单独的文件vendor(与之结合使用CommonsChunkPlugin)vue-router
在webpack 4中不鼓励这样作。相反,该optimization.splitChunks选项负责分离供应商和应用程序模块并建立单独的文件。不要为供应商或其余不是执行起点的东西建立条目。npm
output: {
filename: '[name].bundle.js',
chunkFilename: [name].min.js,
path: path.resolve(__dirname, 'dist'),
publicPath: '/' //确保文件资源可以在 http://localhost:3000 下正确访问
}
复制代码
// dev
devtool: 'eval-source-map'
// prod
devtool: 'source-map'
复制代码
关键字揭秘:
关键字 | 含义 |
---|---|
eval | 在打包的时候,生成的bundle.js文件,模块都被eval包裹,而且后面跟着sourceUrl,指向的是原文件 |
source-map | 这种配置会生成一个带有.map文件,这个map文件会和原始文件作一个映射,调试的时候,就是经过这个.map文件去定位原来的代码位置的 |
cheap | 低消耗打包,就是打包的时候map文件,不会保存原始代码的列位置信息,只包含行位置信息,因此这就解释官网图后面的说明(仅限行) |
... | ... |
devServer: {
compress: true,
port: 9000,
hot: true,
https: true,
overlay: {
warnings: false,
errors: true
},
publicPath: '/platform/redapply/'
}
复制代码
// dev
mode: 'development'
// build
mode: 'production'
复制代码
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
]
复制代码
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
}
复制代码
对于loader的执行顺序,是从后往前的
resolve: {
extensions: ['.js','.ts', '.vue', '.json'],
alias: {
'@lib': resolve('src/lib'),
'@models': resolve('build/models'),
'@components': resolve('src/components'),
'@data': resolve('src/data'),
'@': resolve('src')
}
}
复制代码
好比定义一些公共的scss文件。为了避免再每一个页面都引入该文件。咱们能够设置文件预加载
module: {
rules: [
...
{
test: /\.sass|scss|css$/,
use: [
...
{
loader: 'sass-resources-loader',
options: {
resources: [
path.resolve(__dirname, '../src/assets/css/vars.scss'),
path.resolve(__dirname, '../src/assets/css/common.scss')
]
}
}
]
}
]
}
复制代码
optimization: {
minimize: true, // 默认为true,效果就是压缩js代码。
minimizer: [ // 压缩时调用的插件
new TerserPlugin(),
new OptimizeCSSAssetsPlugin({})
],
runtimeChunk: { // 默认为false,抽离出运行时公共代码块。
name: 'manifest'
},
splitChunks:{
chunks: 'all', // 必须三选一: "initial" | "all"(推荐) | "async" (默认就是async)
minSize: 30000, // 生成块的最小字节数,30000
minChunks: 1, // 最少被引用的次数
maxAsyncRequests: 3, // 按需加载时候最大的并行请求数
maxInitialRequests: 3, // 一个入口最大的并行请求数
name: true, // 打包的chunks的名字
cacheGroups: { // 缓存配置
common: {
name: 'common', // 要缓存的 分隔出来的 chunk 名称
chunks: 'initial', // 必须三选一: "initial" | "all" | "async"(默认就是async)
priority: 11,
enforce: true,
reuseExistingChunk: true, // 可设置是否重用该chunk
test: /[\/]node_modules[\/](vue|babel\-polyfill|mint\-ui)/
},
vendor: { // key 为entry中定义的 入口名称
name: 'vendor', // 要缓存的 分隔出来的 chunk 名称
chunks: 'initial', // 必须三选一: "initial" | "all" | "async"(默认就是async)
priority: 10,
enforce: true,
reuseExistingChunk: true, // 可设置是否重用该chunk
test: /node_modules\/(.*)\.js/
},
styles: {
name: 'styles',
test: /\.(scss|css)$/,
chunks: 'all',
minChunks: 1,
reuseExistingChunk: true,
enforce: true
}
}
}
}
复制代码
默认为false, 抽离出运行时公共代码块
什么是运行时(runtime)?
JS在浏览器中能够调用浏览器提供的API,如window对象,DOM相关API等。这些接口并非由V8引擎提供的,是存在与浏览器当中的。所以简单来讲,对于这些相关的外部接口,能够在运行时供JS调用,以及JS的事件循环(Event Loop)和事件队列(Callback Queue),把这些称为RunTime。有些地方也把JS所用到的core lib核心库也看做RunTime的一部分。
chunk运行时
在chunk执行的时候所依赖的环境(方法)
function (chunk) | string
这表示将选择哪些块进行优化
string:
function:
splitChunks: {
chunks (chunk) {
// exclude `my-excluded-chunk`
return chunk.name !== 'my-excluded-chunk';
}
}
复制代码
缓存组能够继承和/或覆盖任何选项splitChunks.*;要禁用任何默认缓存组,请将其设置为false。
optimization: {
splitChunks: {
chunks: 'async',
minSize: 30000,
minChunks: 1,
maxAsyncRequests: 3,
maxInitialRequests: 3,
name: true,
cacheGroups: {
common: {
name: 'common',
chunks: 'initial',
priority: 11,
enforce: true,
reuseExistingChunk: true, // 可设置是否重用该chunk
test: /[\/|\\]node_modules[\/|\\](vue|babel\-polyfill|mint\-ui)/
},
vendor: {
name: "vendor",
chunks: "initial",
priority: 10,
test: /[\/|\\]node_modules[\/|\\](.*)\.js/
},
styles: {
name: 'styles',
test: /\.(scss|css|less)$/,
chunks: 'initial',
minChunks: 1,
reuseExistingChunk: true,
enforce: true
}
}
}
}
复制代码
注意:
这里有个坑,就是关于test匹配路径的问题 通常网上看到的如:
...
common: {
name: 'common',
chunks: 'initial',
priority: 11,
enforce: true,
reuseExistingChunk: true,
test: /[\/]node_modules[\/](vue|babel\-polyfill|mint\-ui)/
}
...
复制代码
这里面test匹配正则是根据linux环境路径匹配的。(如:node_modules/vue)
但window路径和linux路径不同,它是反斜杠。(如:node_modules\vue)
这样咱们要把正则改为
/[\/|\\]node_modules[\/|\\](vue|babel\-polyfill|mint\-ui)/
复制代码
这样就能够兼容两种环境了
一般来说webpack就须要3个配置文件
但在咱们的项目里你们看到的配置和上面介绍的并不彻底相同。
是由于:咱们在脚手架生成项目的时候,已经集成了webpack的基本配置。
它们都在@zz/webpack-vue下
而咱们项目中仅暴露了一些配置对象入口。
暴露出来的配置项结构和webpack自己的略有区别。
开发人员能够经过自定义这些对象,而后程序会和默认的配置进行合并,造成最终的配置参数。
(本文为内部专题学习webpack的一次分享,内容比较基础)