首先,vue.config.js 文件必须要导出一个对象【涉及到模块概念】
module.exports = {};
对象属性详解
# publicPath
部署生产环境和开发环境的URL。默认值是 /
,表示绝对路径的根目录下
默认情况下,Vue CLI会假设你的应用是被部署在一个域名的根路径上。例如:https://www.my-app.com/
。
如果应用时部署在一个子路径上,你就需要用这个选项指定子路径。例如:如果你的应用被部署在 https://www.my-app.com/my-app/
,则设置值为 /my-app/
。
在 Vue CLI 3.3 之后,baseUrl 已弃用,官方推荐用 publicPath
,有趣的是我们可以通过设置相对路径提高包的适用范围,后续会提及
// process.env.NODE_ENV 是 vue cli 官方提供的变量,直接使用就可以,用来判断是生成环境还是开发环境,也就是判断是通过vue cli 本地运行,还是打包后部署到线上运行
// 以下是目前所开发项目中的常见配置
publicPath: process.env.NODE_ENV === 'production' ? './' : '/'
# outputDir
默认值为 dist
,意味在执行打包命令后会在项目下生成一个名为 dist
的文件夹
在终端执行 npm run build 或 yarn build 后,生成的包文件的文件名称(这里必须和 publicPath 的生成环境路径一致,也就是打包部署到线上时,这里的值必须和publicPath的值保持一致)
举例: 假设你使用默认值,并将该打包生成的文件直接放在服务器https://www.my-app.com/
的根目录下,那访问路径就是 https://www.my-app.com/dist
, 为确保图片、文件等资源路径匹配不出错,publicPath【资源路径】的值就必须为 /dist/
,且在打包之后包的名称不能修改,否则就会出现请求资源地址错误,很明显,则太死板了,因此我们在需要打包之前将 publicPath 设置为相对路径 ./
, 这样寻找资源时便会自动匹配当前目录下路径,也就提高了包的适用范围
// 如果你将值修改为 mydist, 那打包后的文件夹名称变为 mydist
outputDir: 'dist'
# assetsDir
打包后用于放置生成的静态资源(js、css、img、fonts)的文件名称,默认值为 ''
这里需要注意的是当这里为默认值的时候打包后的文件格式一般如下
- dist
- css
- img
- js
... ...
当该属性设置值之后包结构会变为如下:
- dist
- 【assetsDir值】
- css
- img
- js
... ...
assetsDir: '',
# indexPath
默认值为 index.html
打包后的 .html
文件【入口文件】的 “[路径,]名称”,默认打包后生成的 .html
文件名为 index.html
// 将值修改为 my.html,打包后的入口文件名称也会变为 my.html
indexPath: 'my.html'
# filenameHashing
默认值为 true
,修改为 false
关闭为文件添加 .hash值
默认情况下,生成的静态资源在它们的文件名中包含了 hash 以便更好的控制缓存。简单来说打包后的图片、js、icon等等资源文件由原先的 “名称.类型” 变为了 “名称.hash值.类型”。 例如:pic.png
变为 pic.82b9c7a4.png
这里需要注意的是,如果你在项目中并非是动态的添加图资源请求路径,大可不用担心会找不到图片,因为打包之后静态的资源地址也会被执行相应的处理。
以获取一张图片为例:
// 项目中代码如下
background: url('../assets/wq.jpg');
// 开发时控制台查看
background: url('../img/wq.7a8c6db5.jpg');
// 部署在服务器上时控制台查看
background: url('../img/wq.7a8c6db5.jpg');
可以看出来 webpack
已经做了相应的处理,也许你会奇怪,为什么会出现相对路径 ../
首先这里需要提到两个有趣的 vue cli
默认行为:
-
在项目assets文件夹下的所有图片资源无论嵌套多深【指文件夹嵌套】,在打包完成后,所有图片都会安置到
img
文件夹下。举例:// 项目中 - assets - a - 1.jpg - b - 2.png - c - 3.jpeg // 打包后 - dist - img - 1.jpg - 2.png - 3.jpeg
这里有必要提一句:若未检测到项目中有引用,assets 下图片是不会被打包的【这里可以自己测试一下,我只验证了一种情况,静态引用,但动态引用未测试】
-
public
文件夹具有特殊性,在其下建立img
文件夹,img
文件夹【后续文件夹改叫目录吧,这样字可以少打一点】下的文件和目录结构会被完整保留。并且里面的内容不会被webpack
解析,换句话说,即使你 设置filenameHashing: true
,public
目录下的文件也不会有任何变动。
另外经过测试,如果直接在public
目录下建立一个名称不为img
的目录,放置在项目中被引入的图片,该目录下所有图片都会安置到 包 的img
目录下,且不会保留原有的目录结构,但图片不会被进行filenameHashing
处理【也就是不会在名称后面添加.hash值
】。
其他类型资源情况一样遵循上面的行为规律,只是 js
文件是在 public
下建立 js
文件夹,css
文件是在 public
下建立 css
文件夹
我设置的 assetsDir
默认值为 ''
,因此 包结构 为:
- dist
- css
- img
- js
... ...
css
文件被解析到 css
目录下,要找到图片,因此使用 ../
回退到 img
目录层级,然后到 img
目录下寻找对应图片,更多详情进入拓展:vue 图片引入相关问题
filenameHashing: true,
# pages
默认值 undefined
在多页模式【multi-page
模式】下构建应用。我们一般构建的都是单页应用,这个属性让其保持默认值就好。我自己对于多页模式并不了解,一下是搜寻的资料。
问题 :这种多页模式 既不是传统的 MPA 多页模式,也是 SPA 单页模式,更像是一种一次性生成多个单页应用的方式,多个单页应用之间可以共享组件、方法和状态
解答:在不使用 vue-cli 高封装的 api 的时候我们想要配置打包出多个页面,需要使用 html-webpack-plugin插件输出一个 html 文件,多页面就配饰多个 new HtmlWebpackPlugin() 即可
多页面并不是为了减少首屏的渲染问题,更不是路由美化,要知道前端是从多页面 jsp 页面渲染 走到如今前后端分离,spa 的时代,当然多页面首屏一定程度上确实比单页面好些,但这个不是它的目的,多页面的使用场景:
- 对 seo 有要求的项目
- 传统后台插入主流框架开发
资料片传送门
pages: undefined
# lintOnSave
默认值 true
,是否使用 eslint
,true
表示启用,反之,禁用
如果你想要在生产构建时禁用 eslint,你可以用 process.env.NODE_ENV !== 'production';
注意,这个属性在 @vue/cli-plugin-eslint
被安装后生效
lintOnSave: process.env.NODE_ENV !== 'production';
# runtimeCompiler
默认值:false
是否使用包含 “运行时编译器” 的 Vue构建版本【这里的构建是名称,不是动词】,设置 true 后就可以在 Vue 组件中使用 template选项了,但是这会让你的应用【打包后的文件】额外增加 110kb 左右。
runtimeCompiler: false
# transpileDependencies
默认值为 false
生产源映射:项目打包后,代码都是经过压缩加密的,如果运行时报错,输出的错误信息无法准确得知是哪里的代码报错。如果设置该属性值为true
,打包后就会生成相应的 .map
文件,用来准确映射是开发时的那一行那一列出错
如果设置为 false
可以加大打包时的速度,如果发现打包后的项目体积过大,将该值设为 false
就可以不输出 .map
文件,减少体积。
productionSourceMap: false
# crossorigin
默认为 undefined
设置生成的 HTML
中的 <link rel="stylesheet">
和 <script>
标签 crossorigin
属性
需要注意的是该选项仅影响由 html-webpack-plugin 在构建时注入的标签 - 直接写在模板(public/index.html)中的标签不受影响
crossorigin: undefined
# integrity
在生成的 HTML
中的 <link rel="stylesheet">
和 <script>
标签上启用 Subresource Integrity(SRI)
如果你构建后的文件是部署在 CDN 上的, 启用该选项可以提供额外的安全性
需要注意的是该选项仅影响由 html-webpack-plugin 在构建时注入的标签 - 直接写在模板(public/index.html
)中的标签不受影响
另外,当启用 SRI
时,preload resource hints
会被禁用,因为 Chrome
的一个 bug
会导致文件被下载两次
integrity: false
# configureWebpack 和 chainWebpack
与 webpack
的配置有关,目前还未掌握
# css
类型: ,不可以是一个空对象,会报错
css.requireModuleExtension
默认为 true
,默认情况下,只有 *.module.[ext]
结尾的文件才会被视作 CSS Modules
模块。
设置 false
后你就可以去掉文件名中的 .module
并将所有的 *.(css|scss|sass|less|styl(us)?)
文件视为 [CSS Modules
模块
CSS Modules 模块概念:核心原理是使用 js 来管理样式依赖,表现形式是,每个 css 页面都可以像 js 模块一样被引用,用一个个模块搭建样式,减少重复代码,防止多人开发命名冲突。(如有不对,敬请指正)
CSS: {
requireModuleExtension: true
}
css.extract
类型:<boolean | object>,
默认值: 生产环境下是 true
,开发环境下是 false
, 是否将组件中的 CSS 提取至一个独立的 CSS 文件中 (而不是动态的注入到 Javascript 中的 inline 代码)。同样当构建 web Components 组件时它总是会被禁用(样式是 inline 的 并注入到 了 shadowRoot 中)。当作为一个库构建时,你也可以将其设置为 false
免得用户自己导入 CSS。提取CSS在开发环境模式下是默认不开启的,因为它和 CSS 热重载不兼容。然而,你仍可以将这个值显性的设置为 true
在所有情况下都强制提取
CSS: {
extract: process.env.NODE_ENV === 'production'
}
css.loaderOption
向 css
相关的 加载程序传递选项
比如下面的例子就是全局注入变量,其余文件不再需要先引入 @import 'variables.(sass|scss|styl(us)?)'
文件,才能使用该文件内定义的变量,而是可以直接使用
/* - variables.sass */
$src: '~@/img/logo.png';
$pad-t-xs: 10px;
... ...
》loaderOption.sass
给 sass.loader 传递选项,示例演示说明
- @/ 是 src/ 的别名,所以这里假设你有
src/variables.sass
和src/variables2.sass
这两个文件 - 注意:在
sass-loader v7
下的版本中,这个选项是prependData
css: { loaderOpton: { sass: { data: '@import "~@/variables.sass",@import "~@/variables2.sass"' }, /* 默认情况下 sass 选项会同时对 sass 和 scss 语法生效 * 因为scss语法在内部也是 sass-loader 处理的 * 但是配置 data 选项时, * scss语法要求语句结尾必须有分号, sass则要求必须没有分号 * 在这种情况下我们可以使用 scss 选项,对 scss 语法进行单独配置 */ scss: { data: '@import "~@/variables.scss";,@import "~@/variables2.scss";' }, css: { // 这里的选项会传递给 css 的处理程序 }, postcss: { // 这里的选项会传递给 postcss 的处理程序 } ... ... } }
# devServer
类型:<string | object>,所有 webpack-dev-server 的选项 都支持。注意:
- 有些值像
host
、port
和https
可能会被命令行参数覆写 - 有些值像
publicPath
和historyApiFallback
不应该被修改,因为它们需要和开发服务器的publicPath
同步以保障正常的工作
下面是经常使用的一些属性:
devServer.host
类型:<string>
, 默认值是 localhost
。
指定使用一个 host
。默认是 localhost
。如果你希望服务器外部可访问【指别的电脑通过 你的主机名:端口号/path 可以访问你的页面】,指定如下:
devServer: {
host: '0.0.0.0'
}
devServer.port
指定要监听请求的端口号
devServer: {
port: 8080
}
devServer.https
默认值为 true
,默认情况下 dev-server 通过 HTTP 提供服务。也可以选择带有 HTTPS 的 HTTP/2 提供服务【设置为 false
】
devServer: {
https: false
}
devServer.open
告诉dev-server 在server 启用后打开浏览器。默认值 true
,禁用
devServer: {
open: false
}
devServer.hotOnly
与 devServer.hot 配套使用, hot 属性功能为启用 模块热替换,会在应用程序运行过程中,替换、添加或删除 模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度:
- 保留在完全重新加载页面期间丢失的应用程序状态。
- 只更新变更内容,以节省宝贵的开发时间。
- 在源代码中对 CSS/JS 进行修改,会立刻在浏览器中进行更新,这几乎相当于在浏览器 devtools 直接更改样式。
注意: 必须要有 [webpack.HotModuleReplacementPlugin](https://webpack.docschina.org/plugins/hot-module-replacement-plugin/)
才能完全启用 HMR
【模块热替换】
hotOnly 属性在启用热模块替换,在构建失败时不需要刷新页面作为回退。
devServer: {
hot: true,
hotOnly: true
}
devServer.disableHostCheck
设置为 true 时,此选项绕过主机检查。不建议这样做,因为不检查主机的应用程序容易受到 DNS 重新连接攻击。
用于解决问题:访问webpack启动的server,直接使用 localhost
和127.0.0.1
都可以正常访问,但是修改了 host
,使用hostname【主机名称】
访问,就会显示 invalid host header
devServer: {
disableHostCheck: true
}
devServer.proxy
如果你的前端应用和后端 API 没有运行在统一主机上,你需要在开发环境将 API 请求代理到 API 服务器。
这个问题可以通过 vue.config.js
中的 devServer.proxy
选项来配置
devServer.proxy
可以是一个指向开发环境 API 服务器的字符串
proxy: 'http://localhost:4000'
, // 这会告诉服务器将任何未知请求(没有匹配到静态文件的请求)代理到 http://localhost:4000
如果你想要更多的代理控制行为,也可以使用一个 path: options
成对的对象。完整的选项可以查阅 http-proxy-middleware
devServer{
proxy: {
'/api': { // -> 匹配需要代理的接口,共有三种匹配方式
target: 'http://www.example.org', // -> 代理的目标接口地址
/* 当该属性设置为 false时,请求头中 host 仍然是浏览器发送过来的 host,反之,请求头中的 host 会设置成 target
本地会虚拟一个服务端接受你的请求并代你发送该请求
加了这个,代理服务器会在请求头中加入相应Host首部,
然后目标服务器就可以根据这个首部来区别要访问的站点了。
假如你在本地80端口起了apache服务器,服务器配了两个虚拟
站点a.com b.com,设置代理之后并且changeOrigin为true 。
此时就可以正确方法问道虚拟主机下的文档内容。
否则访问a b站点等同于访问localhost。webpack dev sever用的
是node-http-proxy, 你可以找这个相关的资料。
-- 资料来源网络论坛
但经过测试,无论设置该属性为 true 还是 false,在控制
台都会看到请求体中存在 Host,且值为 http://localhost:8080
(或者 http://本地主机名:8080)
*/
changeOrigin: true, // -> 具体每太懂
// ws: true, // -> 在请求为websockets方式时开启
// autoRewrite: true, // -> 功能不详
pathRewrite: { // -> 路径重写
// 修改路径,将代理请求地址http://www.example.org/api/old-path 修改为 http://www.example.org/api/new-path
'^/api/old-path': '/api/new-path',
// 删除路径,将代理请求地址http://www.example.org/api/remove 修改为 http://www.example.org
'^/api/remove': '',
},
}
}
}
给出一个简单的参考配置:
const proxyUrl = 'http://192.168.11.63:9090';
// 预载入变量定义
const loadCss = [
'variables.scss',
'mixins.scss',
];
// vue.config.js
module.exports = {
// 部署应用的基础URL<String>
publicPath: process.env.NODE_ENV === 'production' ? './' : '/',
// 运行时将生成构建文件的目录<String>
outputDir: dist,
// 是否需要生产源映射<Boolean>
productionSourceMap: false,
// 全局注入 scss 变量
css: {
loaderOptions: {
scss: {
data: loadCss.map(v => `@import "@/styles/common/${v}";`).join(''),
},
},
},
// 开发服务配置
devServer: {
host: '0.0.0.0',
port: 8080, // 端口号
https: false, // https: Boolean
open: false, // 自动启动浏览器
hotOnly: true,
disableHostCheck: true,
proxy: {
// 常规接口
'/api': {
target: `${proxyUrl}/api/`,
changeOrigin: true,
pathRewrite: {
'^/api': '',
},
},
// 权限接口
'/api/proxy': {
target: `${proxyUrl}/api/proxy`,
changeOrigin: true,
pathRewrite: {
'^/api/proxy': '',
},
},
// 系统接口
'/api/sinoyd-frame': {
target: `${proxyUrl}/api/sinoyd-frame`,
changeOrigin: true,
pathRewrite: {
'^/api/sinoyd-frame': '',
},
},
// 存储接口(附件或图片映射)
'/api/sinoyd-doc': {
target: `${proxyUrl}/api/sinoyd-doc`,
changeOrigin: true,
pathRewrite: {
'^/api/sinoyd-doc': '',
},
},
},
},
};
参考文献:
CSS Modules 模块概念
http-proxy-middleware
问答论坛
Vue CLI 官网
Webpack 开发中配置