作者: 王振州 时间: 2020-12-17
Vue cli
是一个基于 Vue.js
进行快速开发的完整系统, 有三个组件:
cli
:@vue/cli
全局安装的 npm 包,提供了终端里的 vue
命令(如:vue create 、vue serve 、vue ui
等命令)
cli 服务
:@vue/cli-service
是一个开发环境依赖。构建于 webpack 和 webpack-dev-server
之上(提供 如:serve、build 和 inspect
命令)
cli 插件
:给 Vue 项目提供可选功能的 npm
包 (如: Babel 转译、ESLint 集成、unit 和 e2e 测试
等)
vue-cli(1.x 或 2.x)
要先卸载它,否则跳过此步:npm uninstall vue-cli -g
# or
yarn global remove vue-cli
@vue/cli
(Vue cli 3
的包名称由 vue-cli 改成了 @vue/cli)npm install -g @vue/cli
# or
yarn global add @vue/cli
vue -V
vue --version
vue create <Project Name>
<Project Name>: 文件名 不支持驼峰(含大写字母)
? Please pick a preset
❯ oms (vue-router, vuex, dart-sass, babel, typescript, pwa, unit-jest) // 自定义保存的预设(之前我保存的)
micro-front-end (vue-router, vuex, dart-sass, babel, pwa, eslint, unit-mocha, e2e-cypress) // 自定义保存的预设(之前我保存的)
default (babel, eslint) // 默认设置非常适合快速创建一个新项目的原型,没有带任何辅助功能的 npm 包
Manually select features // 自定义配置是我们所需要的面向生产的项目,提供可选功能的 npm 包
括号中的 npm 包是选择项选择后自动配置到项目中的, 如果选择最后一个(Manually select features
)的话, 就会进行下一步选择配置项, 否则就会使用选择的预设或配置项进行生成项目
? Check the features needed for your project:
◉ Babel // 转码器,可以将ES6代码转为ES5代码,从而在现有环境执行。
◯ TypeScript // TypeScript是一个JavaScript(后缀.js)的超集(后缀.ts)包含并扩展了 JavaScript 的语法,需要被编译输出为 JavaScript在浏览器运行,目前较少人再用
◯ Progressive Web App (PWA) Support // 渐进式Web应用程序
◉ Router // vue-router(vue路由)
◉ Vuex // vuex(vue的状态管理模式)
◉ CSS Pre-processors // CSS 预处理器(如:less、sass)
◉ Linter / Formatter // 代码风格检查和格式化(如:ESlint)
❯◉ Unit Testing // 单元测试(unit tests)
◯ E2E Testing // e2e(end to end) 测试
选择完后直接enter
,然后会提示你选择对应功能的具体工具包, 本项目选择的是上面◉
的选项
Vue-Router 利用了浏览器自身的 hash 模式和 history 模式的特性来实现前端路由
为什么要选 dart-sass, 而不是 node-sass?
vue-cli4 默认选择的是 dart-sass
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default):
Sass/SCSS (with dart-sass)
❯ Sass/SCSS (with node-sass)
Less
Stylus
主要为 css 解决浏览器兼容、简化 CSS 代码 等问题, 本项目使用的是Sass/SCSS (with node-sass)
? Pick a linter / formatter config:
ESLint with error prevention only
ESLint + Airbnb config
ESLint + Standard config
❯ ESLint + Prettier
提供一个插件化的 javascript 代码检测工具,ESLint + Prettier
使用较多
❯◉ Lint on save // 保存时
◯ Lint and fix on commit // commit时检测和修复
? Pick a unit testing solution:
Mocha + Chai //mocha灵活,只提供简单的测试结构,如果需要其他功能需要添加其他库/插件完成。必须在全局环境中安装
❯◉ Jest //安装配置简单,容易上手。内置Istanbul,可以查看到测试覆盖率,相较于Mocha:配置简洁、测试代码简洁、易于和babel集成、内置丰富的expect
Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? (Use arrow keys)
❯ In dedicated config files // 单独文件存放
In package.json // 存放在package.json中
Save this as a preset for future projects? (y/N)
等命令运行完成项目就搭建完, 可以进入(cd
)到对应的目录运行(yarn serve
)
vue.config.js
是一个可选的配置文件,如果项目的 (和 package.json
同级的) 根目录中存在这个文件,那么它会被 @vue/cli-service
自动加载。你也可以使用 package.json
中的vue
字段,但是注意这种写法需要你严格遵照 JSON
的格式来写。
在说配置之前插播一下
process.env.NODE_ENV
的值process.env.NODE_ENV
的值是执行命令是注入的临时 env 环境变量, 在该项目中, 开发环境默认的development
, 发布环境默认是production
设置方式:window
环境set key=value
Mac/Linux
环境:export key=value
; 命令窗口关闭自动销毁
下面是项目中关于 vue.config.js
的配置
// 关于下面三个插件会在后面进行详细介绍
// 代码压缩(内容)混淆插件
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
// 文件压缩(编码方式)插件
const CompressionPlugin = require("compression-webpack-plugin");
// 打包文件分析插件
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer/lib/BundleAnalyzerPlugin");
const path = require("path");
// 成产环境gzip文件的后缀
const productionGzipExtensions = ["js", "css"];
// 拼接文件路径(相对路径==>绝对路径)
function resolve(dir) {
return path.join(__dirname, dir);
}
module.exports = {
// 部署应用包时的基本 URL , (默认'/')
baseUrl: process.env.NODE_ENV === "development" ? "/" : "./",
outputDir: "dist", // 运行时生成的生产环境构建文件的目录(默认''dist'',构建之前会被清除)
assetsDir: "", // 放置生成的静态资源(js、css、img、fonts)的(相对于 outputDir 的)目录(默认'')
indexPath: "index.html", // 指定生成的 index.html 的输出路径(相对于 outputDir)也可以是一个绝对路径。
pages: {
//pages 里配置的路径和文件名在你的文档目录必须存在 否则启动服务会报错
index: {
//除了 entry 之外都是可选的
entry: "src/index/main.js", // page 的入口,每个“page”应该有一个对应的 JavaScript 入口文件
template: "public/index.html", // 模板来源
filename: "index.html", // 在 dist/index.html 的输出
title: "国土空间规划一张图实施监督系统", // 当使用 title 选项时,在 template 中使用:<title><%= htmlWebpackPlugin.options.title %></title>
chunks: ["chunk-vendors", "chunk-common", "index"], // 在这个页面中包含的块,默认情况下会包含,提取出来的通用 chunk 和 vendor chunk
},
},
// 开发环境本地服务配置
devServer: {
host: "0.0.0.0", // host
port: 9096, // 端口号
open: true, // 是否默认打开浏览器
},
// 默认情况下 babel-loader 会忽略所有 node_modules 中的文件。
// 如果你想要通过 Babel 显式转译一个依赖,可以在这个选项中列出来。
// vue-echarts-v3需要babel转码,才能兼容ie
// 参考 https://github.com/xlsdg/vue-echarts-v3#usage
transpileDependencies: ["vue-echarts-v3", "iview"],
css: {
// css预设器配置项
loaderOptions: {
// 给 sass-loader 传递选项
sass: {
// data引入公用文件或全局变量,多个用 ; 进行分割
data: `@import "@/styles/index.scss";`,
},
},
},
// 是否为 Babel 或 TypeScript 使用 thread-loader。该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建
// 在配置中没有看到babel相关配置? 内部使用了cache-loader, 其实内部还是使用了babel-loader @babel/cli @babel/core @babel/preset-env
parallel: false,
// [链式操作](https://cli.vuejs.org/zh/guide/webpack.html#链式操作-高级)
// 基于[webpack-chain](https://github.com/neutrinojs/webpack-chain), 这个库提供了一个 webpack 原始配置的上层抽象,使其可以定义具名的 loader 规则和具名插件等,并有机会在后期进入这些规则并对它们的选项进行修改。它允许我们更细粒度的控制其内部配置。添加新的loader 删除loader 修改loader等
chainWebpack: (config) => {
// 设置别名
config.resolve.alias
.set("@", resolve("src"))
.set("YZT", resolve("src/views/YZT"))
.set("JDGL", resolve("src/views/JDGL"))
.set("FZBZ", resolve("src/views/FZBZ"))
.set("JCYJ", resolve("src/views/JCYJ"))
.set("ZBMX", resolve("src/views/ZBMX"))
.set("YWXT", resolve("src/views/YWXT"))
.set("MXXT", resolve("src/views/MXXT"))
.set("FZSC", resolve("src/views/FZSC"));
// 鼠标指针样式
config.module
.rule("mouse")
.test(/\.(ico|cur)(\?.*)?$/)
.use("file-loader")
.loader("file-loader")
.options({
name: "[path][name].[ext]",
})
.end();
// worker-loader
config.module
.rule("worker")
.test(/\.worker\.js$/)
.use("worker-loader")
.loader("worker-loader")
.options({
inline: true,
})
.end();
config.module.rule("js").exclude.add(/\.worker\.js$/);
config.output.globalObject("this");
config.plugin("html").tap((args) => {
if (process.env.NODE_ENV === "development") {
args[0].favicon = path.resolve("public/favicon_dev.ico");
}
return args;
});
// use svg
const svgRule = config.module.rule("svg");
svgRule.uses.clear();
svgRule.include
.add(resolve("src/icon/svg"))
.end()
.use("svg-sprite-loader")
.loader("svg-sprite-loader")
.options({
symbolId: "icon-[name]",
})
.end();
// image exclude svg
const imagesRule = config.module.rule("images");
imagesRule
.test(/\.(png|jpe?g|gif|webp|svg)(\?.*)?$/)
.exclude.add(resolve("src/icon/svg"))
.end();
},
// 该配置会通过 webpack-merge 合并到最终的 webpack 配置中
configureWebpack: {
// 生成的source-map类型
// source-map 原始代码 最好的sourcemap质量有完整的结果,但是会很慢
// eval-source-map 原始代码 同样道理,但是最高的质量和最低的性能
// cheap-module-eval-source-map 原始代码(只有行内) 同样道理,但是更高的质量和更低的性能
// cheap-eval-source-map 转换代码(行内) 每个模块被eval执行,并且sourcemap作为eval的一个dataurl
// eval 生成代码 每个模块都被eval执行,并且存在@sourceURL,带eval的构建模式能cache SourceMap
// cheap-source-map 转换代码(行内) 生成的sourcemap没有列映射,从loaders生成的sourcemap没有被使用
// cheap-module-source-map 原始代码(只有行内) 与上面一样除了每行特点的从loader中进行映射
//
// eval 使用eval包裹模块代码
// source-map 产生.map文件
// cheap 不包含列信息, 也不包含loader的sourcemap
// module 包含loader的sourcemap(比如jsx to js ,babel的sourcemap),否则无法定义源文件
// inline 将.map作为DataURI嵌入,不单独生成.map文件
devtool:
process.env.NODE_ENV === "development"
? "cheap-module-eval-source-map"
: "source-map",
// 优化
// 从 webpack 4 开始,会根据你选择的 mode 来执行不同的优化, 不过所有的优化还是可以手动配置和重写。
optimization: {
// 允许你通过提供一个或多个定制过的 TerserPlugin 实例, 覆盖默认压缩工具(minimizer)。
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
warnings: false, // 是否抛出警告
compress: {
drop_console: false, // 生产环境是否自动去掉console
drop_debugger: true, // 生产环境是否自动去掉debugger
},
},
parallel: true,
sourceMap: true,
}),
],
},
// webpack 插件
plugins:
process.env.NODE_ENV === "production"
? [
// gzip
new CompressionPlugin({
filename: "[path].gz[query]", // 文件名
algorithm: "gzip", // 压缩方式
test: new RegExp(
"\\.(" + productionGzipExtensions.join("|") + ")$"
), // 处理所有匹配此 {RegExp} 的资源
threshold: 10240, // 压缩阈值
minRatio: 0.8, // 压缩比
}),
// webpack 依赖库分析
process.env.npm_config_report
? new BundleAnalyzerPlugin({
analyzerMode: "static",
})
: function none() {},
]
: [],
},
};
字面意思是使 js 丑陋的 webpack 插件, 顾名思义用来压缩 js 文件 使用 uglifyjs 作为核心库; uglifyjs-webpack-plugin 源码地址
// UglifyJsPluginOptions 插件初始化参数
test?: RegExp | RegExp[]; 测试匹配哪些文件 默认 test = /\.js(\?.\*)?\$/i
include?: RegExp | RegExp[]; 包含哪些文件
exclude?: RegExp | RegExp[]; 排除哪些文件
cache?: boolean | string; 是否启用文件缓存,默认缓存在 node_modules/.cache/uglifyjs-webpack-plugin.目录
parallel?: boolean | number; 使用多进程并行运行来提高构建速度 true cpu 核数 - 1
sourceMap?: boolean; 是否生成 sourceMap cheap-source-map 不适用该插件
uglifyOptions?: UglifyJsOptions;
uglifyOptions: {
warnings: false, // 是否抛出警告
compress: {
drop_console: false, // 生产环境是否自动去掉console
drop_debugger: true // 生产环境是否自动去掉debugger
}
}
extractComments?: boolean | RegExp | ((node: object, comment: string) => boolean) | ExtractCommentsOptions;
warningsFilter?: (source: string) => boolean;
// UglifyJsPluginOptions 默认值
const {
minify,
uglifyOptions = {},
test = /\.js(\?.\*)?\$/i,
chunkFilter = () => true,
warningsFilter = () => true,
extractComments = false,
sourceMap = false,
cache = false,
cacheKeys = (defaultCacheKeys) => defaultCacheKeys,
parallel = false,
include,
exclude,
} = options;
参数
Name | Type | Default | Description |
---|---|---|---|
test | {RegExp} | . | 处理所有匹配此 {RegExp} 的资源 |
asset | {String} | [path].gz[query] | 目标资源名称[file] 会被替换成原资源。[path] 会被替换成原资源路径,[query] 替换成原查询字符串 |
filename | {Function} | false | 一个 {Function} (asset) => asset 函数,接收原资源名(通过 asset 选项)返回新资源名 |
algorithm | {String | Function} | gzip |
threshold | {Number} | 0 | 只处理比这个值大的资源。按字节计算 |
minRatio | {Number} | 0.8 | 只有压缩率比这个值小的资源才会被处理 |
deleteOriginalAssets | {Boolean} | false | 是否删除原资源 |
作用是用来提升网络传输速率达到优化 web 页面加载时间的目的
我们知道基于 HTTP 协议, 在发起请求时候会通过 HTTP 请求头告诉服务器它期待服务器采取什么形式的压缩内容, 方便后续的解压缩处理
基本原理
但是有一些问题: 压缩文件耗费服务器 CPU(服务器需要压缩文件、浏览器解压文件) 那么我们就可以借助 CompressionWebpackPlugin 插件来提前对文件进行 Gzip 压缩, 这样服务器查找到有与源文件同名的.gz 文件就会直接读取,不会主动压缩,降低 cpu 负载,优化了服务器性能
node 端 nodejs 很幸福,只需 use 一个 compress 模块
var compression = require("compression");
var app = express();
//尽量在其他中间件前使用 compression
app.use(compression());
tomcat 找到 tomcat 的 server.xml 文件,找到其中 Connector 节点然后进行配置修改,具体配置如下
<Connector port="80"protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" maxPostSize="0" useBodyEncodingForURI="true" compression="on" compressionMinSize="2048" noCompressionUserAgents="gozilla, traviata" compressableMimeType="text/html,text/xml,application/javascript,text/css,text/plain,image/jpeg,application/json"/>
这个插件的功能是生成代码分析报告,帮助提升代码质量和网站性能, 它可以直观分析打包出的文件包含哪些,大小占比如何,模块包含关系,依赖项,文件是否重复,压缩后大小如何,针对这些,我们可以进行文件分割等操作。
项目中配置了report
命令npm_config_report=true vue-cli-service build
, 用于触发 vue.config.js 中配置的该插件
// webpack 依赖库分析
process.env.npm_config_report
? new BundleAnalyzerPlugin({
analyzerMode: "static",
})
: function none() {};
// options 参数
{
// 可以是`server`,`static`或`disabled`。
// 在`server`模式下,分析器将启动HTTP服务器来显示软件包报告。
// 在“static”模式下,会生成带有报告的单个HTML文件。
// 在`disabled`模式下,你可以使用这个插件来将`generateStatsFile`设置为`true`来生成Webpack Stats JSON文件。
"analyzerMode": "server",
// 将在“服务器”模式下使用的主机启动HTTP服务器。
"analyzerHost": "127.0.0.1",
// 将在“服务器”模式下使用的端口启动HTTP服务器。
"analyzerPort": 8888,
// 路径捆绑,将在`static`模式下生成的报告文件。
// 相对于捆绑输出目录。
"reportFilename": "report.html",
// 模块大小默认显示在报告中。
// 应该是`stat`,`parsed`或者`gzip`中的一个。
// 有关更多信息,请参见“定义”一节。
"defaultSizes": "parsed",
// 在默认浏览器中自动打开报告
"openAnalyzer": true,
// 如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成
"generateStatsFile": false,
// 如果`generateStatsFile`为`true`,将会生成Webpack Stats JSON文件的名字。
// 相对于捆绑输出目录。
"statsFilename": "stats.json",
// stats.toJson()方法的选项。
// 例如,您可以使用`source:false`选项排除统计文件中模块的来源。
// 在这里查看更多选项:https: //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
"statsOptions": null,
"logLevel": "info" // 日志级别。可以是'信息','警告','错误'或'沉默'。
}