一,认识webpack
Webpack 是一个打包模块化 JavaScript 的工具,在 Webpack 里一切文件皆模块,通过 Loader 转换文件,通过 Plugin 注入钩子,最后输出由多个模块组合成的文件。Webpack 专注于构建模块化项目。
其实说它是打包工具有点大材小用了,我个人认为它是一个集前端自动化、模块化、组件化于一体的可拓展系统,你可以根据自己的需要来进行一系列的配置和安装,最终实现你需要的功能并进行打包输出。
一切文件:JavaScript、CSS、SCSS、图片、模板,在 Webpack 眼中都是一个个模块,这样的好处是能清晰的描述出各个模块之间的依赖关系,以方便 Webpack 对模块进行组合和打包。 经过 Webpack 的处理,最终会输出浏览器能使用的静态资源。
在Vue的项目中,webpack 具有重要作用,比如打包压缩、异步加载、模块化管理等等。
二,webpack的使用
1. vue-cli 2.x 与 vue-cli 3.x 的差异
如果使用过 vue-cli 2.x,那么你应该了解其构建出的目录会包含相应的 webpack 配置文件,但是在 vue-cli 3.x 中你却见不到一份关于 webpack 的配置文件,cli 3.x 提供了一种开箱即用的模式,即你无需配置 webpack 就可以运行项目,并且它提供了一个 vue.config.js 文件来满足开发者对其封装的 webpack 默认配置的扩展和修改。如图(cli-3.xx 配置):
cli 2.xx 的配置文件图
对比可以看出cli 3.x 去除繁杂的各式配置文件,统一到单独文件中让开发者独自扩展项目的配置。
2. vue.config.js 的配置
通过上方的对比,我们可以清晰的看出 vue.config.js 的配置项结构,构建出来的项目默认没有该配置文件,那么你需要在根目录手动创建它。其中常用配置项的功能和用途:
(1). baseurl
我们通过 vue-cli 3.x 成功构建并在浏览器中打开 http://localhost:8080/ 展示了项目首页。如果现在你想要将项目地址加一个二级目录,比如:http://localhost:8080/vue/,那么我们需要在 vue.config.js 里配置 baseurl 这一项(从 Vue CLI 3.3 起已弃用,请使用publicPath):
// vue.config.js
module.exports = {
...
baseUrl: 'vue',
...
}
其改变的其实是 webpack 配置文件中 output 的 publicPath 项,这时候你重启终端再次打开页面的时候我们首页的 url 就会变成带二级目录的形式。
(2). outputDir
如果你想将构建好的文件打包输出到 output 文件夹下(默认是 dist 文件夹),你可以配置:
// vue.config.js
module.exports = {
...
outputDir: 'dist', //默认dist
...
}
然后运行命令 npm run build 进行打包输出,你会发现项目跟目录会创建 dist 文件夹, 这其实改变了 webpack 配置中 output 下的 path 项,修改了文件的输出路径。
(3).productionSourceMap
该配置项用于设置是否为生产环境构建生成 source map,一般在生产环境下为了快速定位错误信息,我们都会开启 source map:
// vue.config.js
module.exports = {
...
productionSourceMap: true,
...
}
该配置会修改 webpack 中 devtool 项的值为 source-map。
开启 source map 后,我们打包输出的文件中会包含 js 对应的 .map 文件,其用途可以参考:JavaScript Source Map 详解
(4). devServer
vue.config.js 还提供了 devServer 项用于配置 webpack-dev-server 的行为,使得我们可以对本地服务器进行相应配置,我们在命令行中运行的 npm run serve 对应的命令 vue-cli-service serve 其实便是基于 webpack-dev-server 开启的一个本地服务器,其常用配置参数如下:
// vue.config.js
module.exports = {
...
devServer: {
open: true, // 是否自动打开浏览器页面
host: '0.0.0.0', // 指定使用一个 host。默认是 localhost
port: 8080, // 端口地址
https: false, // 使用https提供服务
// proxy: null, // string | Object 代理设置 一般处理跨域请求转发
proxy: {
'/repos': { //匹配到 /repos 字符串 自动转发到target地址上
target: 'https://api.github.com', //转发地址
changeOrigin: true
// pathRewrite: {'^/api': ''} //重写地址
}
},
// 提供在服务器内部的其他中间件之前执行自定义中间件的能力
before: app => {
// `app` 是一个 express 实例
}
}
...
}
(5). chainWebpack
chainWebpack 配置项允许我们更细粒度的控制 webpack 的内部配置,其集成的是 webpack-chain 这一插件,该插件可以让我们能够使用链式操作来修改配置,比如:
// 用于做相应的合并处理
const merge = require('webpack-merge');
module.exports = {
...
chainWebpack: (config) => {
config.module.rules.delete('svg') // 重点:删除默认配置中处理svg,
config.resolve.alias
.set('@', resolve('src'))
.set('~lib', resolve('src/common'))
.set('~com', resolve('src/components'))
config.module
.rule('svg')
.exclude.add(resolve('src/assets/icons'))
.end()
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/assets/icons')) // 处理svg目录
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
//配置 rules 规则为图片下的 url-loader 值
config.module
.rule('images')
.use('url-loader')
.tap(options =>
merge(options, {
limit: 5120,
})
)
},
...
}
以上操作我们可以成功修改 webpack 中 module 项里配置 rules 规则为图片下的 url-loader 值,将其 limit 限制改为 5M,配置规则 为icons的svg-sprite-loader值 使用 修改后的 webpack 配置代码如下:
{
...
module: {
rules: [
{
/* config.module.rule('images') */
test: /.(png|jpe?g|gif|webp)(?.*)?$/,
use: [
/* config.module.rule('images').use('url-loader') */
{
loader: 'url-loader',
options: {
limit: 5120,
name: 'img/[name].[hash:8].[ext]'
}
}
]
}
]
}
...
}
这里需要注意的是我们使用了 webpack-merge 这一插件,该插件用于做 webpack 配置的合并处理,这样 options 下面的其他值就不会被覆盖或改变。 关于 webpack-chain 的使用可以参考其 github 官方地址:github.com/mozilla-neu…,它提供了操作类似 JavaScript Set 和 Map 的方式,以及一系列速记方法。
(6). configureWebpack
除了上述使用 chainWebpack 来改变 webpack 内部配置外,我们还可以使用 configureWebpack 来进行修改,两者的不同点在于 chainWebpack 是链式修改,而 configureWebpack 更倾向于整体替换和修改。示例代码如下:
// vue.config.js
module.exports = {
...
// config 参数为已经解析好的 webpack 配置
configureWebpack: config => {
// config.plugins = []; // 这样会直接将 plugins 置空
// 使用 return 一个对象会通过 webpack-merge 进行合并,plugins 不会置空
return {
plugins: []
}
}
...
}
configureWebpack 可以直接是一个对象,也可以是一个函数,如果是对象它会直接使用 webpack-merge 对其进行合并处理,如果是函数,你可以直接使用其 config 参数来修改 webpack 中的配置,或者返回一个对象来进行 merge 处理。
你可以在项目目录下运行 vue inspect 来查看你修改后的 webpack 完整配置,当然你也可以缩小审查范围,比如:
# 只查看 plugins 的内容
vue inspect plugins
以上讲解了 vue.config.js 中一些常用的配置项功能,具体的配置实现需要结合实际项目进行,完整的配置项可以查看:vue.config.js
三,其他
-
filenameHashing : 默认情况下,生成的静态资源在它们的文件名中包含了 hash 以便更好的控制缓存。然而,这也要求 index 的 HTML 是被 Vue CLI 自动生成的。如果你无法使用 Vue CLI 生成的 index HTML,你可以通过将这个选项设为
false来关闭文件名哈希。 -
pages: 在 multi-page 模式下构建应用。每个“page”应该有一个对应的 JavaScript 入口文件。其值应该是一个对象,对象的 key 是入口的名字,value 是:
一个指定了
entry,template,filename,title和chunks的对象 (除了entry之外都是可选的);一个指定其
entry的字符串。module.exports = { pages: { index: { // page 的入口 entry: 'src/index/main.js', // 模板来源 template: 'public/index.html', // 在 dist/index.html 的输出 filename: 'index.html', // 当使用 title 选项时, // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title> title: 'Index Page', // 在这个页面中包含的块,默认情况下会包含 // 提取出来的通用 chunk 和 vendor chunk。 chunks: ['chunk-vendors', 'chunk-common', 'index'] }, // 当使用只有入口的字符串格式时, // 模板会被推导为 `public/subpage.html` // 并且如果找不到的话,就回退到 `public/index.html`。 // 输出文件名会被推导为 `subpage.html`。 subpage: 'src/subpage/main.js' } } -
css
css: { modules: true, sourceMap:true, // 是否为 CSS 开启 source map。设置为 `true` 之后可能会影响构建的性能。 loaderOptions: { css: { localIdentName: '[name]-[hash]', camelCase: 'only' } } }css.modules 默认情况下,只有
*.module.[ext]结尾的文件才会被视作 CSS Modules 模块。设置为true后你就可以去掉文件名中的.module并将所有的*.(css|scss|sass|less|styl(us)?)文件视为 CSS Modules 模块。css.loaderOptions:向 CSS 相关的 loader 传递选项。例如: ``` module.exports = { css: { loaderOptions: { css: { // 这里的选项会传递给 css-loader }, postcss: { // 这里的选项会传递给 postcss-loader } } } } ```