贴上官网
vue-cli3 创建的时候并不会自动创建vue.config.js,因为这个是个可选项,所以一般都是需要修改webpack的时候才会自己创建一个vue.config.js
再然后因为vue-cli3内部高度集成了webpack,一般来说使用者不需要再去知道weboack做了什么,所以没有暴露webpack的配置文件,我们可以手动去创建vue.config.js 去修改默认的webpack。注意,只能叫vue.config.js。
-
在根目录中创建 vue.config.js
vue.config.js配置
贴上我在项目中,用到的比较全的配置
"use strict";
const path = require("path");
function resolve(dir) {
return path.join(__dirname, dir);
}
module.exports = {
// 部署应用时的基本 URL
publicPath:
process.env.NODE_ENV === "production"
? `/${process.env.VUE_APP_BASE_URL}`
: "/",
// build时构建文件的目录 构建时传入 --no-clean 可关闭该行为
outputDir: "dist",
// build时放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录
assetsDir: "",
// 指定生成的 index.html 的输出路径 (相对于 outputDir)。也可以是一个绝对路径。
indexPath: "index.html",
// 默认在生成的静态资源文件名中包含hash以控制缓存
filenameHashing: true,
// 是否在开发环境下通过 eslint-loader 在每次保存时 lint 代码 (在生产构建时禁用 eslint-loader)
lintOnSave: process.env.NODE_ENV !== "production",
// 是否使用包含运行时编译器的 Vue 构建版本
runtimeCompiler: false,
// Babel 显式转译列表
transpileDependencies: [],
// 设置生成的 HTML 中 <link rel="stylesheet"> 和 <script> 标签的 crossorigin 属性(注:仅影响构建时注入的标签)
crossorigin: "",
// 在生成的 HTML 中的 <link rel="stylesheet"> 和 <script> 标签上启用 Subresource Integrity (SRI)
integrity: false,
// 如果这个值是一个对象,则会通过 webpack-merge 合并到最终的配置中
// 如果你需要基于环境有条件地配置行为,或者想要直接修改配置,那就换成一个函数 (该函数会在环境变量被设置之后懒执行)。该方法的第一个参数会收到已经解析好的配置。在函数内,你可以直接修改配置,或者返回一个将会被合并的对象
configureWebpack: { devtool: "source-map" },
// 对内部的 webpack 配置(比如修改、增加Loader选项)(链式操作)
productionSourceMap: process.env.NODE_ENV === "development", // 是否在构建生产包时生成sourcdeMap
// productionSourceMap: true, // 是否在构建生产包时生成sourcdeMap
chainWebpack: config => {
config.entry("main").add("@babel/polyfill");
config.plugin("html").tap(args => {
args[0].title = "测试";
return args;
});
config.resolve.alias.set("@", resolve("src"));
const svgRule = config.module.rule("svg");
// 清除已有的所有loader
svgRule.uses.clear();
svgRule
.test(/\.svg$/)
.include.add(path.resolve(__dirname, "./src/assets/icons"))
.end()
.use("svg-sprite-loader")
.loader("svg-sprite-loader")
.options({
symbolId: "icon-[name]"
});
},
// css的处理
// 所有 webpack-dev-server 的选项都支持
devServer: {
host: "0.0.0.0", //局域网和本地访问
port: "8089",
hot: true,
/* 自动打开浏览器 */
open: false,
overlay: {
warning: false,
error: true
},
/* 跨域代理 */
proxy: {
[process.env.VUE_APP_BASE_API]: {
/* 目标代理服务器地址 */
// target: process.env.VUE_APP_BASE_URI,
target: "http://xxx/xx",
/* 允许跨域 */
changeOrigin: true,
ws: true,
pathRewrite: {
// "^/dev-api": ""
["^" + process.env.VUE_APP_BASE_API]: ""
}
}
}
},
// 是否为 Babel 或 TypeScript 使用 thread-loader
parallel: require("os").cpus().length > 1,
// 向 PWA 插件传递选项
pwa: {},
// 可以用来传递任何第三方插件选项
pluginOptions: {},
css: {
loaderOptions: {
postcss: {
plugins: [
require("postcss-pxtorem")({
rootValue: 37.5, // 换算的基数,数值具体看你的设计稿 另外提醒下vant-UI的官方根字体大小是37.5
selectorBlackList: [], // 忽略转换正则匹配项
unitPrecision: 3,
propList: ["*"], // 需要做转化处理的属性,如`hight`、`width`、`margin`等,`*`表示全部
minPixelValue: 3 // 小于或等于`3px`不转换为视窗单位
})
]
},
less: {
modifyVars: {
hack: `true; @import "${resolve("./src/assets/styles/reset.less")}";`
}
}
}
}
};
配置选项解析
publicPath(从 Vue CLI 3.3 起已弃用baseUrl,请使用publicPath)
参考:https://my.oschina.net/u/4446873/blog/4882847
Type: string
Default: '/'
部署应用包时的基本 URL, 用法和 webpack 本身的 output.publicPath 一致。
这个值也可以被设置为空字符串 ('') 或是相对路径 ('./'),这样所有的资源都会被链接为相对路径,这样打出来的包可以被部署在任意路径。
默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上,例如https://www.xxx.com/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在https://www.xxx.com/my-app/,则设置 publicPath 为 /my-app/。
这个值在开发环境下同样生效。如果你想把开发服务器架设在根路径
,你可以使用一个条件式的值:
module.exports={
//基本路径
publicPath:process.env.NODE\_ENV=== 'production' ? '/haining-Admin/' : '/'
}
通常开发环境,本地运行都会直接部署在根路径上,publicPath设置为'/',访问地址是你的IP地址。如下是设置成'/app'的效果:
从上面可以得知,静态资源文件都是在app下的,所以在dist下新增添一个app目录,把dist下文件放到app下,相当于一个文件的路径,可以发现项目会正常启动。一般nginx都会配置一个静态资源目录,打包后的文件都会放到这个静态资源目录里面,nginx去做映射,所以publicPath这个属性基本不用改。'/'就行。
结论:publicPath配置成'/aaa/bbb/ccc', 则需在相应的服务器路径中新建aaa>bbb>ccc的文件夹,然后将打包后的文件放进去,就ok啦。
项目中,我会在.env.production文件中设置一个变量VUE_APP_BASE_URL ,项目打包后告诉相关人员 nginx 路由前缀是什么即可
# nginx 路由前缀
VUE_APP_BASE_URL = 'ancientCms'
这里补充一下: base和publicpath
如果在history路由模式下,一般改配置的话,两个都要一起改。publicpath针对的是项目部署的路径问题, base针对的是页面路由url的路径问题,缺一不可。
outputDir
Type: string
Default: 'dist'
输出文件目录,当运行 vue-cli-service build 时生成的生产环境构建文件的目录。注意目标目录在构建之前会被清除 (构建时传入 --no-clean 可关闭该行为)。
module.exports={
//build时构建文件的目录
outputDir: "dist",
}
assetsDir
Type: string
Default: ''
build时放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。
注:从生成的资源覆写 filename 或 chunkFilename 时,assetsDir 会被忽略。
module.exports={
//build时放置静态资源的目录
assetsDir: "static",
}
indexPath
Type: string
Default: 'index.html'
指定生成的 index.html 的输出路径 (相对于 outputDir)。也可以是一个绝对路径。
module.exports={
//html 的输出路径
indexPath: "index.html",
}
filenameHashing
Type: boolean
Default: true
默认情况下,生成的静态资源在它们的文件名中包含了 hash 以便更好的控制缓存。然而,这也要求 index 的 HTML 是被 Vue CLI 自动生成的。如果你无法使用 Vue CLI 生成的 index HTML,你可以通过将这个选项设为 false 来关闭文件名哈希
module.exports={
//默认在生成的静态资源文件名中包含hash以控制缓存
filenameHashing: true,
}
直观效果:当运行npm run build时,
打包后的文件后面都会带一个8位的hash值,那啥是个hash值?
在打包出来的文件名上加上文件内容的hash是目前最常见的有效使用浏览器长缓存的方法,js文件如果有内容更新,hash就会更新,浏览器请求路径变化所以更新缓存,如果js内容不变,hash不变,直接用缓存。(这段话是从别的文章里面参考的)。
将filenameHashing这个值设置为false试试,就不会带那个后缀hash值。
pages
Type: Object
Default: undefined
在 multi-page(多页)模式下构建应用。每个“page”应该有一个对应的 JavaScript 入口文件。
module.exports={
pages:{
index:{
//page的入口文件
entry:'src/index/main.js',
//模板文件
template:'public/index.html',
// 在 dist/index.html 的输出
filename:'index.html',
//当使用页面titlt选项时,
// template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
title:'Index Page',
// 在这个页面中包含的块,默认情况下会包含
// 提取出来的通用 chunk 和 vendor chunk。
chunks:['chunk-vendors','chunk-common','index']
},
subpage:'src/subpage/main.js'
},
}
lintOnSave
Type:
boolean
|'warning'
|'default'
|'error'
Default:'default'
是否在开发环境下通过 eslint-loader 在每次保存时 lint 代码。这个值会在@vue/cli-plugin-eslint
被安装之后生效。
设置为true
或'warning'
时,eslint-loader
会将 lint 错误输出为编译警告。默认情况下,警告仅仅会被输出到命令行,且不会使得编译失败。
module.exports = {
//是否在开发环境下通过 eslint-loader 在每次保存时 lint 代码 (在生产构建时禁用 eslint-loader)
lintOnSave: process.env.NODE_ENV !== 'production'
}
runtimeCompiler
Type: boolean
Default: false
是否使用包含运行时编译器的 Vue 构建版本。设置为 true 后你就可以在 Vue 组件中使用 template 选项了,但是这会让你的应用额外增加 10kb 左右。
module.exports = {
// 是否使用包含运行时编译器的 Vue 构建版本
runtimeCompiler: false,
}
transpileDependencies
Type: Array<string | RegExp>
Default: []
默认情况下 babel-loader 会忽略所有 node_modules 中的文件。如果你想要通过 Babel 显式转译一个依赖,可以在这个选项中列出来。
module.exports = {
// Babel 显式转译列表
transpileDependencies: [],
}
productionSourceMap
Type: boolean
Default: true
如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
module.exports = {
// 是否在构建生产包时生成sourcdeMap
productionSourceMap: process.env.NODE_ENV === "development",
}
crossorigin(不理解)
Type: string
Default: undefined
设置生成的 HTML 中 <link rel="stylesheet"> 和 <script> 标签的 crossorigin 属性。
需要注意的是该选项仅影响由 html-webpack-plugin 在构建时注入的标签 - 直接写在模版 (public/index.html) 中的标签不受影响。
module.exports = {
// 设置生成的 HTML 中 <link rel="stylesheet"> 和 <script> 标签的 crossorigin 属性(注:仅影响构建时注入的标签)
crossorigin: "",
}
integrity
Type: boolean
Default: false
在生成的 HTML 中的 <link rel="stylesheet"> 和 <script> 标签上启用 Subresource Integrity (SRI)。如果你构建后的文件是部署在 CDN 上的,启用该选项可以提供额外的安全性。
module.exports = {
// 在生成的 HTML 中的 <link rel="stylesheet"> 和 <script> 标签上启用 Subresource Integrity (SRI)
integrity: false,
}
- Webpack相关配置
configureWebpack
Type: Object | Function
除了上述使用 chainWebpack 来改变 webpack 内部配置外,我们还可以使用 configureWebpack 来进行修改,两者的不同点在于 chainWebpack 是链式修改,而 configureWebpack 更倾向于整体替换和修改。
configureWebpack: { devtool: "source-map" },
chainWebpack
Type: Object | Function
chainWebpack 配置项允许我们更细粒度的控制 webpack 的内部配置,其集成的是 webpack-chain这一插件,该插件可以让我们能够使用链式操作来修改配置
chainWebpack: config => {
config.resolve.alias
.set('common', resolve('src/common'))
.set('components', resolve('src/components'))
.set('http', resolve('src/http'))
.set('base', resolve('src/base'))
.set('views', resolve('src/views'))
.set('store', resolve('src/store'))
.set('filters', resolve('src/filters'))
.set('directives', resolve('src/directives'))
.set('router', resolve('src/router'));
config.plugin('preload').tap(() => [
{
rel: 'preload',
fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
include: 'initial',
},
]);
config.plugins.delete('prefetch');
config.plugin('provide').use(webpack.ProvidePlugin, [{
'window.Quill': 'quill'
}])
},
Css相关配置
css: {
loaderOptions: {
postcss: {
plugins: [
require("postcss-pxtorem")({
rootValue: 37.5, // 换算的基数,数值具体看你的设计稿 另外提醒下vant-UI的官方根字体大小是37.5
selectorBlackList: [], // 忽略转换正则匹配项
unitPrecision: 3,
propList: ["*"], // 需要做转化处理的属性,如`hight`、`width`、`margin`等,`*`表示全部
minPixelValue: 3 // 小于或等于`3px`不转换为视窗单位
})
]
},
less: {
modifyVars: {
hack: `true; @import "${resolve("./src/assets/styles/reset.less")}";`
}
}
}
}
devServer
如果你的前端应用和后端 API 服务器没有运行在同一个主机上,你需要在开发环境下将 API 请求代理到 API 服务器。这个问题可以通过 vue.config.js 中的 devServer.proxy 选项来配置。
补充知识
所谓的跨域就是不同源,不满足协议、域名、端口都相同的约定
http://www.test.com/dir/login.html 同源
https://www.test.com/index.html 不同源 协议不同(https)
http://www.test.com:90/index.html 不同源 端口不同(90)
http://www.demo.com/index.html 不同源 域名不同(demo)
当协议、域名、端口中任意一个不相同时,就是不同源。若不同源之间相互请求资源,就算作跨域
补充知识
反向代理(Reverse Proxy)方式是指以代理服务器来接受网络上的连接请求,然后将请求转发给内部网络上的服务器,并将服务器上得到的结果返回给请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。客户端无需做任何配置。
修改config/index.js /vue.config.js文件(改完之后千万记得要重新 npm run dev)
module.exports = {
devServer: {
host: "0.0.0.0", //同一局域网下可以用前端的本地地址访问
port: "7978",
hot: true,
/* 自动打开浏览器 */
open: false,
overlay: {
warning: false,
error: true
},
/* 跨域代理 */
proxy: {
[process.env.VUE_APP_BASE_API]: {
/* 目标代理服务器地址 */
// target: process.env.VUE_APP_BASE_URI, //
target: "http://xxx/xx", //
/* 允许跨域 */
changeOrigin: true,
ws: true,
pathRewrite: {
// "^/dev-api": ""
["^" + process.env.VUE_APP_BASE_API]: ""
}
}
}
},
}
derServer下的参数配置
host 将他的值修改为 0.0.0.0,代表可以访问本机所有的IP地址,让vue项目可通过localhost和IP同时访问。
Type: string
Default: localhost
作用:用于指定devDerve使用的host。
port 设置端口号
Type: number
作用: 指定要监听请求的端口号
open 是否在第一次编译时是自动打开浏览器
Type: boolean | string
Default: false
作用:用于设置 server 启动后是否自动打开浏览器。
hot 开启为true,启动热重载,自动刷新页面
Type: boolean | string
Default: true
作用:用于设置代码保存时是否进行热更新(局部刷新,不刷新整个页面)。
hot和hotOnly的区别
- hot: true
单纯设置为true的时候,如果编译报错,会抛出错误,你重新改成正确的,这个时候又会触发重新编译,整个浏览器会重新刷新! - hotOnly: true
这个也设置的话,如果编译报错,你再改成正确的,重新编译,浏览器不会刷新!
区别在于,刷新,有些复现步骤比较复杂的话,刷掉了浏览器,要一步步重新点。
hot 和 hotOnly 的区别是在某些模块不支持热更新的情况下,前者会自动刷新页面,后者不会刷新页面,而是在控制台输出热更新失败
https
Type: boolean | object
Default: false
作用:用于设置是否启用https
inline
Type: boolean | string
Default: true
作用:用于设置代码保存时是否自动刷新页面。
overlay
overlay: { // 错误、警告在页面弹出
warning: false,
error: true
},
proxy下的参数配置
/* 跨域代理 */
proxy: {
'/api/': {
/* 目标代理服务器地址 */
target: "http://localhost:8080", //
/* 允许跨域 */
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api/': ""
}
}
}
targe 代理的服务器,也就是api要访问的服务器。
changeOrigin 允许跨域, 为false时,请求头中host仍然是浏览器发送过来的host;如果设置成true:发送请求头中host会设置成target的值
ws 是否代理websocket
pathRewrite 重写 url 的 path 部分
问:pathRewrite里面的'^/api/'是什么意思?
答:用代理,首先你得有一个标识,告诉他,带有/api/的连接要用代理,不然可能html,css,js这些静态资源都跑去代理。所以我们只要接口用代理,静态文件用本地。
'/api/':{},就是告诉node,我接口只要是'/api/'开头的才用代理,所以你的接口就要这么写:'/api/xx/xx',最后代理的路径就是:http://xxx.xx.com/api/xx/xx
可是不对啊,正确的接口路径里面没有/api啊,所以就需要pathRewrite,用 '^/api/':'',把/api给去掉,这样既能有正确的表示,又能在请求接口的时候去掉api。
此文记录下来,方便自己遗忘的时候能够快速查阅,如有错误请指出。
参考链接:
https://www.jianshu.com/p/b358a91bdf2d
https://www.jb51.net/article/174200.htm
https://blog.csdn.net/liu_yunzhao/article/details/90520028
这篇文章讲的也很详细https://blog.csdn.net/guozhangqiang/article/details/87197870