介绍
- Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统
- 通过 @vue/cli 搭建交互式的项目脚手架。
- 通过 @vue/cli + @vue/cli-service-global 快速开始零配置原型开发。
- 一个运行时依赖 (@vue/cli-service) 一个开发环境依赖,局部安装在每个 @vue/cli 创建的项目中。
- 可升级 ?
- 基于 webpack 构建,并带有合理的默认配置;
- 可以通过项目内的配置文件进行配置;
- 可以通过插件进行扩展。—— cli 插件是用来给 webpack 安装 loader包或插件包的工具,同时它能够自动的完成这些包的配置。
- 一个丰富的官方插件集合,集成了前端生态中最好的工具。
- 一套完全图形化的创建和管理 Vue.js 项目的用户界面。
- Vue CLI 致力于将 Vue 生态中的工具基础标准化。
该系统的组件
CLI
- @vue/cli 提供了终端里的 vue 命令
- vue create 快速创建一个新项目的脚手架
- vue serve 构建新想法的原型
- vue ui 通过一套图形化界面管理你的所有项目
CLI 服务
- @vue/cli-service 是一个开发环境依赖,局部安装在每个 @vue/cli 创建的项目中。
- CLI 服务是构建于 webpack 和 webpack-dev-server 之上
- 加载其它 CLI 插件的核心服务
- 一个针对绝大部分应用优化过的内部的 webpack 配置
- 项目内部的 vue-cli-service 命令,提供 serve、build 和 inspect 命令 (inspect 来审查一个 Vue CLI 项目的 webpack config)
CLI 插件
- CLI 插件是向你的 Vue 项目提供可选功能的 npm 包,例如 Babel/TypeScript 转译、ESLint 集成、单元测试和 end-to-end 测试等。
- Vue CLI 插件的名字以 @vue/cli-plugin- (内建插件) 或 vue-cli-plugin- (社区插件) 开头
- 当你在项目内部运行 vue-cli-service 命令时,它会自动解析并加载 package.json 中列出的所有 CLI 插件。
- 插件可以作为项目创建过程的一部分,或在后期加入到项目中。
————————————————————————————————————————————————————————————
安装
- Vue CLI 需要 Node.js 8.9 或更高版本 (推荐 8.11.0+)
- 可以使用 nvm 或 nvm-windows 在同一台电脑中管理多个 Node 版本。
- 安装之后,你就可以在命令行中访问 vue 命令。
- 可以用这个命令来检查其版本是否正确
vue --version
—— 返回@vue/cli的版本号
————————————————————————————————————————————————————————————
基础
————————————————————————————————————————————————————————————
快速原型开发
- 可以使用 vue serve 和 vue build 命令对单个 *.vue 文件进行快速原型开发
- 需要先额外安装一个全局的扩展
npm install -g @vue/cli-service-global
(不一定需要全局安装)
vue serve
- 在开发环境模式下零配置为 .js 或 .vue 文件启动一个服务器,用法:
vue serve [options] [entry]
- Options:
- -o, --open 打开浏览器
- -c, --copy 将本地 URL 复制到剪切板
- -h, --help 输出用法信息
- vue serve 使用了 vue create 的默认设置 (webpack、Babel、PostCSS 和 ESLint)。
- 入口可以是 main.js、index.js、App.vue 或 app.vue 中的一个,在命令
vue serve
执行的当前目录下 - 可以显式地指定入口文件
vue serve MyComponent.vue
或vue serve ccc/first.vue
,从命令行执行的位置起 - 可以提供一个 index.html —— 放在命令运行目录下或其public内,如果没有将使用标准html作为模板
- 可以提供一个 package.json
- 可以安装并使用本地依赖
- 可以通过相应的配置文件配置 Babel、PostCSS 和 ESLint
vue build
- 在生产环境模式下零配置将目标文件构建成一个生产环境的包并用来部署(一个 .js 或 .vue 文件),用法:
vue build [options] [entry]
,例如:vue build MyComponent.vue
(更多路径书写方法见vue serve) - 也提供了将组件构建成为一个库或一个 Web Components 组件的能力。(对于4种构建目标的区别将在后文进行研究)
- Options:
- -t, --target
构建目标 (app | lib | wc | wc-async, 默认值:app) - -n, --name
库的名字或 Web Components 组件的名字 (wc 和 wc-async 默认值:入口文件名,并要求必须有连字符) (lib 时默认值是package.json 中的 "name" 字段) - -d, --dest
输出目录 (默认值:dist) - -h, --help 输出用法信息
- -t, --target
————————————————————————————————————————————————————————————
创建一个项目
vue create
- 创建一个由
vue-cli-service
提供支持的新项目,用法create [options]
,例如:vue create hello-world
- 在 Windows 上通过 minTTY 使用 Git Bash,交互提示符并不工作 ——?
- 通过 winpty vue.cmd create hello-world 启动
vue create hello-world
这个命令 - 可以通过在 ~/.bashrc 文件中添加以下行来为命令添加别名
alias vue='winpty vue.cmd'
来支持vue create hello-world
,需要重新启动 Git Bash 终端会话以使更新后的 bashrc 文件生效
- 通过 winpty vue.cmd create hello-world 启动
- 在操作提示的最后你可以选择将已选项保存为一个将来可复用的 preset
- 被保存的 preset 将会存在用户的 home 目录下一个名为 .vuerc 的 JSON 文件里。保存多套,操作提示的最后会让你输入每套配置的名称,已被将来选择
- 在项目创建的过程中,你也会被提示选择喜欢的包管理器或使用淘宝 npm 镜像源以更快地安装依赖。
- 这些选择也将会存入 ~/.vuerc。
- 选项:
- -p, --preset
忽略提示符并使用已保存的或远程的预设选项 ? - -d, --default 忽略提示符并使用默认预设选项
- -i, --inlinePreset
忽略提示符并使用内联的 JSON 字符串预设选项 ? - -m, --packageManager
在安装依赖时使用指定的 npm 客户端 - -r, --registry
在安装依赖时使用指定的 npm registry - -g, --git [message] 强制 / 跳过 git 初始化,并可选的指定初始化提交信息 ?
- -n, --no-git 跳过 git 初始化 ?
- -f, --force 覆写目标目录可能存在的配置
- -c, --clone 使用 git clone 获取远程预设选项 ?
- -x, --proxy 使用指定的代理创建项目 ?
- -b, --bare 创建项目时省略默认组件中的新手指导信息
- -h, --help 输出使用帮助信息
- -p, --preset
使用图形化界面
- 可以通过 vue ui 命令以图形化界面创建和管理项目
拉取 2.x 模板 (旧版本)
- Vue CLI 3 和旧版使用了相同的 vue 命令,所以 Vue CLI 2 (vue-cli) 被覆盖了。
- 可以全局安装一个桥接工具,使用旧版本的 vue init 功能
npm install -g @vue/cli-init
?
————————————————————————————————————————————————————————————
插件和Preset
插件
- 插件可以修改 webpack 的内部配置,也可以向 vue-cli-service 注入命令
- 在项目创建的过程中,绝大部分列出的特性都是通过插件来实现的
- 特性:比如使用ESLint管理状态就是其中一种特性
- 可以通过 vue ui 命令使用 GUI(图形界面) 安装和管理插件
在现有的项目中安装插件
- 每个 CLI 插件都会包含一个生成器和一个运行时插件
- 生成器用来创建文件的(应该是指从npm上安装对应的模块,例如Eslint)
- 运行时插件用来调整 webpack 核心配置和注入命令的(运行时是指?注入命令是指? )
- 使用 vue create 来创建一个新项目的时候,有些插件会根据你选择的特性被预安装
- 在一个已经被创建好的项目中安装一个插件,可以使用 vue add 命令
vue add @vue/eslint
- 和
vue add @vue/cli-plugin-eslint
等价 - 这个命令将 @vue/eslint 解析为完整的包名 @vue/cli-plugin-eslint,然后从 npm 安装它,调用它的生成器。(依然能够向项目中插入插件定义的命令,例如
vue add @vue/eslint
后会在package中新增"lint": "vue-cli-service lint"
命令)
- 和
- 如果不带 @vue 前缀,该命令会换作解析一个 unscoped 的包。例如以下命令会安装第三方插件 vue-cli-plugin-apollo:
vue add apollo
- 可以基于一个指定的 scope(范围) 使用第三方插件。例如如果一个插件名为 @foo/vue-cli-plugin-bar,你可以这样添加它:
vue add @foo/bar
- 可以基于一个指定的 scope(范围) 使用第三方插件。例如如果一个插件名为 @foo/vue-cli-plugin-bar,你可以这样添加它:
- 可以向被安装的插件传递生成器选项 (这样做会跳过命令提示):
vue add @vue/eslint --config airbnb --lintOn save
- vue-router 和 vuex 的情况比较特殊——它们并没有自己的插件,但是你仍然可以这样添加它们:
vue add router
vue add vuex
- 如果一个插件已经被安装,你可以使用 vue invoke 命令跳过安装过程,只调用它的生成器。?
- 这个命令会接受和 vue add 相同的参数。
- 如果出于一些原因你的插件列在了该项目之外的其它 package.json 文件里,你可以在自己项目的 package.json 里设置 vuePlugins.resolveFrom 选项指向包含其它 package.json 的文件夹。?
// 如果你有一个 .config/package.json 文件
{
"vuePlugins": {
"resolveFrom": ".config"
}
}
- 推荐在运行 vue add 之前将项目的最新状态提交,因为该命令可能调用插件的文件生成器并很有可能更改你现有的文件。
项目本地的插件 ?
- 在项目里直接访问插件 API 而不需要创建一个完整的插件 ?
- 可以通过 vuePlugins.ui 选项添加像 UI 插件一样工作的文件 ?
- 该章节涉及插件开发和高级应用,暂时看不懂 ?
Preset(预设.vuerc文件)
- Vue CLI preset 是一个包含创建新项目所需预定义选项和插件的 JSON 对象
- 在 vue create 过程中保存的 preset 会被放在你的 home 目录下的一个配置文件中 (~/.vuerc)
- Preset 的数据会被插件生成器用来生成相应的项目文件(Preset中保存这插件以及和这个插件相关的提示符选项所以能够被插件生成器生成相应的项目文件)
- 可以为集成工具添加配置:这些额外的配置将会根据 useConfigFiles 的值被合并到 package.json 或相应的配置文件中。(当有多个项目通用自定义vue.config.js配置时,可以在这里编辑,方便创建项目时不用重复配置)
{
"useConfigFiles": true, // 当 "useConfigFiles": true 的时候,configs 的值将会被合并到 vue.config.js 中
"plugins": {...},
"configs": {
"vue": {...},
"postcss": {...},
"eslintConfig": {...},
"jest": {...}
}
}
Preset 插件的版本管理
- 可以显式地指定用到的插件的版本
- 对于官方插件来说这不是必须的
- 推荐为 preset 列出的所有第三方插件提供显式的版本范围
{
"plugins": {
"@vue/cli-plugin-eslint": {
"version": "^3.0.0",
// ... 该插件的其它选项
}
}
}
允许插件的命令提示
每个插件在项目创建的过程中都可以注入它自己的命令提示
- 当你使用了一个 preset,这些命令提示就会被跳过,因为 Vue CLI 假设所有的插件选项都已经在 preset 中声明过了
- 有些情况下你可能希望 preset 只声明需要的插件,对于这种场景你可以在插件选项中指定 "prompts": true 来允许注入命令提示
{
"plugins": {
"@vue/cli-plugin-eslint": {
// 让用户选取他们自己的 ESLint config
"prompts": true
}
}
}
———————————————————————————
远程 Preset ?
- 可以通过发布 git repo 将一个 preset 分享给其他开发者。这个 repo 应该包含以下文件:
- preset.json: 包含 preset 数据的主要文件(必需)。
- generator.js: 一个可以注入或是修改项目中文件的 Generator(生产者)。
- prompts.js 一个可以通过命令行对话为 generator 收集选项的 prompts(提示) 文件。
- 可以在创建项目的时候通过 --preset 选项使用这个远程的 preset
# 从 GitHub repo 使用 preset(GitLab 和 BitBucket 也是支持的)
# GitHub、GitLab、BitBucket都是仓库管理系统
vue create --preset username/repo my-project
- 如果要从私有 repo 获取,请确保使用 --clone 选项
vue create --preset gitlab:username/repo --clone my-project
vue create --preset bitbucket:username/repo --clone my-project
————————————————————————————
加载文件系统中的 Preset
- 如果 --preset 选项的值是一个相对或绝对文件路径,或是以 .json 结尾,则 Vue CLI 会加载本地的 preset
- 绝对路径:从盘符开始的路径
# ./my-preset 应当是一个包含 preset.json 的文件夹
vue create --preset ./my-preset my-project
# 或者,直接使用当前工作目录下的 json 文件:
vue create --preset my-preset.json my-project
————————————————————————————————————————————————————————————
CLI服务
使用命令
- Vue CLI 项目中,@vue/cli-service 安装了一个名为 vue-cli-service 的命令
- 可以在 npm scripts 中以 vue-cli-service访问这个命令(npm scripts 在默认 preset 的项目的 package.json 中已经配置好了)
- 或者从终端中以 ./node_modules/.bin/vue-cli-service 访问这个命令 ?
- 可以通过 vue ui 命令使用 GUI(视图界面) 运行更多的特性脚本
vue-cli-service serve
- vue-cli-service serve 命令会启动一个开发服务器 (基于 webpack-dev-server) 并附带开箱即用的模块热重载 (Hot-Module-Replacement)。
- 用法
vue-cli-service serve [options] [entry]
- options选项:
- --open 在服务器启动时打开浏览器
- --copy 在服务器启动时将 URL 复制到剪切版
- --mode 指定环境模式 (默认值:development)
- --host 指定 host (默认值:0.0.0.0)
- --port 指定 port (默认值:8080)
- --https 使用 https (默认值:false)
- 除了通过命令行参数,你也可以使用 vue.config.js 里的 devServer 字段配置开发服务器。(待扩展)
vue-cli-service build
- vue-cli-service build 会在 ./dist/ 目录产生一个可用于生产环境的包,带有 JS/CSS/HTML 的压缩,和为更好的缓存而做的自动的 vendor chunk splitting(供应商块拆分)。
- 它的 chunk manifest(块清单) 会内联在 HTML 里。
- 用法:vue-cli-service build [options] [entry|pattern]
- 选项:
- --mode 指定环境模式 (默认值:production(生产))
- --dest 指定输出目录 (默认值:dist)
- --modern 面向现代浏览器带自动回退地构建应用
- --target app | lib | wc | wc-async (默认值:app)
- --name 库或 Web Components 模式下的名字 (默认值:package.json 中的 "name" 字段(lib库时)或入口文件名(Web Components 模式时))
- --no-clean 在构建项目之前不清除目标目录
- --report 生成 report.html 以帮助分析包内容的大小
- --report-json 生成 report.json 以帮助分析包内容的大小
- --watch 监听文件变化(会生成一个热打包的服务)
"build": "vue-cli-service build --target lib ./src/components/HelloWorld.vue"
vue-cli-service inspect
- 使用 vue-cli-service inspect 来审查一个 Vue CLI 项目的 webpack config
- 用法:vue-cli-service inspect [options] [...paths] 例如:
npx vue-cli-service inspect configureWebpack
用来检查webpack中configureWebpack选项的值 - 选项:
- --mode 指定环境模式 (默认值:development)
查看所有的可用命令
- 有些 CLI 插件会向 vue-cli-service 注入额外的命令
- 可以运行以下命令查看所有注入的命令:
npx vue-cli-service help
- 可以这样学习每个命令可用的选项:
npx vue-cli-service help [command]
缓存和并行处理
- cache-loader 会默认为 Vue/Babel/TypeScript 编译开启。文件会缓存在 node_modules/.cache 中——如果你遇到了编译方面的问题,记得先删掉缓存目录之后再试试看。
- thread-loader 会在多核 CPU 的机器上为 Babel/TypeScript 转译开启。
——————————————————————————————————————
Git Hook ?
- @vue/cli-service 会安装 yorkie,它会让你在 package.json 的 gitHooks 字段中方便地指定 Git hook:
- Git hook(Git 钩子)能在特定的重要动作发生时触发自定义脚本。
- yorkie 是husky的一个自定义分支和未来版本的husky不兼容
{
"gitHooks": {
"pre-commit": "lint-staged"
}
}
——————————————————————————————————————
配置时无需 Eject
- 通过 Vue CLI 创建的项目让你无需 eject(计算机命令) 就能够配置工具的几乎每个角落
————————————————————————————————————————————————————————————
开发
————————————————————————————————————————————————————————————
浏览器兼容性
browserslist
- package.json 文件里的 browserslist 字段 (或一个单独的 .browserslistrc 文件),指定了项目的目标浏览器的范围
- 这个值会被 @babel/preset-env 和 Autoprefixer 用来确定需要转译的 JavaScript 特性和需要添加的 CSS 浏览器前缀
Polyfill(是一块代码,用来为旧浏览器提供它没有原生支持的较新的功能。)
useBuiltIns: 'usage'(@vue/babel-preset-env 的配置)
- 一个默认的 Vue CLI 项目会使用 @vue/babel-preset-app,它通过 @babel/preset-env 和 browserslist 配置来决定项目需要的 polyfill
- 默认情况下,它会把 useBuiltIns: 'usage' 传递给 @babel/preset-env,这样它会根据源代码中出现的语言特性自动检测需要的 polyfill。这确保了最终包里 polyfill 数量的最小化。
- 如果其中一个依赖需要特殊的 polyfill,默认情况下 Babel 无法将其检测出来
- 依赖需要 polyfill,你有几种选择
- 如果该依赖交付 ES5 代码,但使用了 ES6+ 特性且没有显式地列出需要的 polyfill (例如 Vuetify):请使用 useBuiltIns: 'entry' 然后在入口文件添加 import '@babel/polyfill'。会根据 browserslist 目标导入所有 polyfill
- Vuetify:一种 vue 移动端的组件库
- Vuetify应该交付了遵循ES5语法的代码(例如:使用var而不是let,cont),但是却用了ES5不支持的对象或对象方法,所以不需要再对该依赖进行语法转换,而只需要导入 polyfill用来支持ES6+ 的新特性
- 但第二种方法也能实现这个功能,而且更好,为什么要采用这种呢?
- 如果该依赖基于一个目标环境不支持的 ES 版本撰写: 将其添加到 vue.config.js 中的 transpileDependencies 选项。这会为该依赖同时开启语法语法转换和根据使用情况检测 polyfill
- 如果该依赖交付了 ES5 代码并显式地列出了需要的 polyfill: 你可以使用 @vue/babel-preset-app 的 polyfills 选项预包含所需要的 polyfill。(如下在 babel.config.js配置)
- es6.promise 将被默认包含,因为现在的库依赖 Promise 是非常普遍的。
- 推荐以这种方式添加 polyfill 而不是在源代码中直接导入它们,因为如果这里列出的 polyfill 在 browserslist 的目标中不需要,则它会被自动排除。
- 如果该依赖交付 ES5 代码,但使用了 ES6+ 特性且没有显式地列出需要的 polyfill (例如 Vuetify):请使用 useBuiltIns: 'entry' 然后在入口文件添加 import '@babel/polyfill'。会根据 browserslist 目标导入所有 polyfill
module.exports = {
transpileDependencies: [
'webpack-dev-server/client',
],
}
// babel.config.js
module.exports = {
presets: [
['@vue/app', {
polyfills: [
'es6.promise',
'es6.symbol' // 一种新的数据类型,表示独一无二的对象
]
}]
]
}
构建库或是 Web Component 时的 Polyfills
- 当使用 Vue CLI 来构建一个库或是 Web Component 时,推荐给 @vue/babel-preset-env 传入 useBuiltIns: false 选项。这能够确保你的库或是组件不包含不必要的 polyfills。通常来说,打包 polyfills 应当是最终使用你的库的应用的责任。
现代模式
vue-cli-service build --modern
会产生两个应用的版本:一个现代版的包,面向支持 ES modules 的现代浏览器,另一个旧版的包,面向不支持的旧浏览器。- 现代版的包会通过
- 它们还会使用 让浏览器优先加载模块
- modulepreload的行为类似于preload
- preload能够指明哪些资源是在页面加载完成后即刻需要的。对于这种即刻需要的资源在页面加载的生命周期的早期阶段就开始获取,在浏览器的主渲染机制介入前就进行预加载。
- 旧版的包会通过
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa' // 指明了属性名为nonce
————————————————————————————————————————————————————————————
HTML和静态资源
HTML
Index 文
public/index.html
文件是一个会被 html-webpack-plugin 处理的模板。在构建过程中,资源链接会被自动注入。- 会自动注入 resource hint 资源提示(preload/prefetch、manifest 和图标链接 (当用到 PWA 插件时) 以及构建过程中处理的 JavaScript 和 CSS 文件的资源链接。
- manifest:属性规定文档的缓存 manifest 的位置。是一个简单的文本文件,列举出了浏览器用于离线访问而缓存的资源。
- 每个指定了 manifest 的页面在用户对其访问时都会被缓存。也可以在文件中声明要缓存的页面
- manifest 文件的建议的文件扩展名是:".appcache"。(具体将在在缓存章节整理)
- 图标链接 (当用到 PWA 插件时) ?
- manifest:属性规定文档的缓存 manifest 的位置。是一个简单的文本文件,列举出了浏览器用于离线访问而缓存的资源。
...
插值
- 因为 index 文件被用作模板,所以你可以使用 lodash 的 template 语法插入内容: ?
- lodash:一个一致性、模块化、高性能的 JavaScript 实用工具库。
<%= VALUE %>
用来做不转义插值;<%- VALUE %>
用来做 HTML 转义插值;<% expression %>
用来描述 JavaScript 流程控制。
// 不转义插值
<%= 'abc' %>
// HTML 转义插值 // 用来描述 JavaScript 流程控制 <% for (var index in htmlWebpackPlugin.options.title) { %><%= htmlWebpackPlugin.options.title[index] %>
<% } %>- 可以使用被 html-webpack-plugin 暴露的默认值 ()
- vue.config.js 内 pages 各个页面的参数?
- 所有客户端环境变量也可以直接使用 (后文介绍到,在.env文件中设置,必须以 VUE_APP_ 开头)
Preload
是一种 resource hint(资源提示),用来指定页面加载后很快会被用到的资源
- 默认情况下,一个 Vue CLI 应用会为所有初始化渲染需要的文件自动生成 preload 提示。
- 这些提示会被 @vue/preload-webpack-plugin 注入,并且可以通过 chainWebpack 的 config.plugin('preload') 进行修改和删除(详情见下文)
Prefetch
是一种 resource hint,用来告诉浏览器在页面加载完成后,利用空闲时间提前获取用户未来可能会访问的内容。
- 默认情况下,一个 Vue CLI 应用会为所有作为 async chunk 生成的 JavaScript 文件自动生成 prefetch 提示。(import()方法导入的异步模块,详见模块导入导出)
- 这些提示会被 @vue/preload-webpack-plugin 注入,并且可以通过 chainWebpack 的 config.plugin('prefetch') 进行修改和删除。
- 删除后,异步模块依然会被单独打包,但是 webpack 的运行时不会在父级区块被加载之后注入
// vue.config.js module.exports = { chainWebpack: config => { // 移除 prefetch 插件 config.plugins.delete('prefetch') // 或者 // 修改它的选项: config.plugin('prefetch').tap(options => { options[0].fileBlacklist = options[0].fileBlacklist || [] options[0].fileBlacklist.push(/myasyncRoute(.)+?\.js$/) return options }) } }
- 当 prefetch 插件被禁用时,你可以通过 webpack 的内联注释手动选定要提前获取的代码区块,webpack 的运行时会在父级区块被加载之后注入 prefetch 链接
- 如果你的应用很大且有很多 async chunk,而用户主要使用的是对带宽较敏感的移动端,那么你可能需要关掉 prefetch 链接并手动选择要提前获取的代码区块。
- 在webpack提供的注释中并没有这个选项;被禁用是指上文提到的移除这个插件吗?
import(/* webpackPrefetch: true */ './someAsyncComponent.vue')
————————————————————————————————————————
不生成 index
- 当基于已有的后端使用 Vue CLI 时,你可能不需要生成 index.html,这样生成的资源可以用于一个服务端渲染的页面
- 硬编码的文件名不利于实现高效率的缓存控制。(什么是服务端渲染?组件在服务端渲染后还需要缓存吗?)
- 硬编码的文件名也无法很好的进行 code-splitting (代码分段),因为无法用变化的文件名生成额外的 JavaScript 文件。?
- 硬编码的文件名无法在现代模式下工作。?
- 应该考虑换用 indexPath 选项将生成的 HTML 用作一个服务端框架的视图模板。
// vue.config.js module.exports = { // 去掉文件名中的 hash,服务端引用可以写死 filenameHashing: false, // 删除 HTML 相关的 webpack 插件 chainWebpack: config => { config.plugins.delete('html') // 仅仅删除html会导致preload和prefetch注入时报错 config.plugins.delete('preload') config.plugins.delete('prefetch') } }
————————————————————————————————————————
构建一个多页应用
- Vue CLI 支持使用 vue.config.js 中的 pages 选项构建一个多页面的应用。
- 构建好的应用将会在不同的入口之间高效共享通用的 chunk 以获得最佳的加载性能。
// vue.config.js配置 module.exports = { pages: { index: { // page 的入口 entry: 'src/index/main.js', // 模板来源 template: 'public/index.html', // 在 dist/index.html 的输出 // 也可以写为`'index/index.html'`这样,html会被打包到index目录内,但是引用的其他资源不会归纳到一起。感觉没有任何意义 // 如果需要部署到根目录以下的次一级目录中,应当修改 process.env.BASE_URL 值,并修改所有绝对引用。所以使用绝对引用时,应当以 process.env.BASE_URL 为前缀。见下文 public 文件夹 的详细说明 filename: 'index.html', // 当使用 title 选项时, // template 中的 title 标签需要是
<%= htmlWebpackPlugin.options.title %> title: 'Index Page', // 在这个页面中包含的块,默认情况下会包含 // 提取出来的通用 chunk 和 vendor chunk。 chunks: ['chunk-vendors', 'chunk-common', 'index'] }, one: { entry: 'src/one/main.js', template: 'public/index.html', filename: 'one.html', title: 'one Page', chunks: ['chunk-vendors', 'chunk-common', 'index'] }, // 当使用只有入口的字符串格式时, // 模板会被推导为 `public/subpage.html` // 并且如果找不到的话,就回退到 `public/index.html`。 // 输出文件名会被推导为 `subpage.html`。 subpage: 'src/subpage/main.js' } } // 每个单页面的路由 export default new Router({ mode: 'history', // 会依据基路由的path去服务器上获取对应名称的html,然后才调用该页面的路由实行渲染。例如,这里会先获取one.html页面,然后加载之上的路由实现渲染。 // 搜索范围可能包括`/one.html``/one/index.html``/one/one.html` base: `${process.env.BASE_URL}one`, routes: [ { path: '/', name: 'home', component: Home }, { path: '/about', name: 'about', // route level code-splitting 路由级代码拆分 // this generates a separate chunk (about.[hash].js) for this route 这将为此路由生成一个单独的块 about.[hash].js // which is lazy-loaded when the route is visited. 当路线被访问时,它被延迟加载 component: () => import(/* webpackChunkName: "about" */ './views/About.vue') } ] }) // 通过a标签在页面中实现跨页面跳转 one About处理静态资源
- 在 JavaScript 被导入或在 template/CSS 中通过相对路径被引用。这类引用会被 webpack 处理。
- 在 JavaScript 被导入
- babel 语法转换和引入polyfill
- chunk:分为供应商块(通过npm安装的块)、通用块(项目内自定义公共组件到达一定的代码级别才独立打包,小型的公共组件会被独立打包到各个异步块中)、异步块、app块(bundle 块)
- base64文件名,实现优化缓存
- template 中通过相对路径被引用,例如
- base64文件名,实现优化缓存
- 图片转为data内嵌
- CSS 中通过相对路径被引用
- 图片转为data内嵌
- 本地环境css都是被内嵌的
- 依据目标浏览器添加前缀
- base64文件名,实现优化缓存
- css中的引用也会被处理,例如
background-image: url(./assets/bg.gif);
- 在 JavaScript 被导入
- 本地开发环境服务时css样式都是嵌入式的,并且都不做base64文件名处理
- 放置在 public 目录下或通过绝对路径被引用。这类资源将会直接被拷贝,而不会经过 webpack 的处理。
从相对路径导入
- 在 JavaScript、CSS 或 *.vue 文件中使用相对路径 (必须以 . 开头) 引用一个静态资源时,该资源将会被包含进入 webpack 的依赖图中。
- 通过webpack设置的@路径,本质上也是相对路径引用
- ../ 代表上一级目录,也是以.开头的
- 在其编译过程中,所有诸如
、background: url(...) 和 CSS @import 的资源 URL 都会被解析为一个模块依赖。
- @import url("fineprint.css");
// 将会被编译为: h('img', { attrs: { src: require('./image.png') }})
- 在其内部,我们通过 file-loader 用版本哈希值和正确的公共基础路径来决定最终的文件路径(公共基础路径是指,例如打包好的js会被统一放到dist\js文件夹中,那么html内部的引用也要随之改变)
- 再用 url-loader 将小于 4kb 的资源内联,以减少 HTTP 请求的数量。
- 可以通过 chainWebpack 调整内联文件的大小限制。例如,下列代码会将其限制设置为 10kb:
// vue.config.js module.exports = { chainWebpack: config => { config.module .rule('images') .use('url-loader') .loader('url-loader') .tap(options => Object.assign(options, { limit: 10240 })) } }
URL 转换规则
- 如果 URL 是一个绝对路径 (例如 /images/foo.png),它将会被保留不变。例如:
(该路径指向的资源及路径本身不会被处理,即html被加载后依然向 /assets/去请求logo.png这个图片) - 如果 URL 以 . 开头,它会作为一个相对模块请求被解释且基于你的文件系统中的目录结构进行解析。
- 如果 URL 以 ~ 开头,其后的任何内容都会作为一个模块请求被解析。这意味着你甚至可以引用 Node 模块中的资源(只发现 css下的用法,不明白这句什么含义?)
- 如果 URL 以 @ 开头,它也会作为一个模块请求被解析。它的用处在于 Vue CLI 默认会设置一个指向
的别名 @。仅作用于模版中?(并不只在模板中被使用,JS中也可以使用,CSS比较特殊请参考后文)/src
public 文件夹
- 任何放置在 public 文件夹的静态资源都会被简单的复制,而不经过 webpack。你需要通过绝对路径来引用它们。(会被直接复制到 /dist 目录下)
- 我们推荐将资源作为你的模块依赖图的一部分导入,这样它们会通过 webpack 的处理并获得如下好处:
- 脚本和样式表会被压缩且打包在一起,从而避免额外的网络请求。
- 文件丢失会直接在编译时报错,而不是到了用户端才产生 404 错误。
- 最终生成的文件名包含了内容哈希,因此你不必担心浏览器会缓存它们的老版本。
- 会自动生成合适的引用路径,不必担心部署问题
- public 目录提供的是一个应急手段,当你通过绝对路径引用它时,留意应用将会部署到哪里。如果你的应用没有部署在域名的根部,那么你需要为你的 URL 配置 publicPath 前缀:
- 绝对路径引用时必须以 process.env.BASE_URL 为前缀,这是为了方便项目的日后维护
- 可以把process.env.BASE_URL视为项目部署时的前缀目录
// 在 public/index.html 或其它通过 html-webpack-plugin 用作模板的 HTML 文件中,你需要通过 <%= BASE_URL %> 设置链接前缀: // 在模板中,你首先需要向你的组件传入基础 URL: data () { return { publicPath: process.env.BASE_URL } }
何时使用 public 文件夹
- 你需要在构建输出中指定一个文件的名字。?
- 你有上千个图片,需要动态引用它们的路径 ?
- 有些库可能和 webpack 不兼容,这时你除了将其用一个独立的
注册多个 Web Components 组件的包
- 当你构建一个 Web Components 组件包的时候,你也可以使用一个 glob 表达式作为入口指定多个组件目标:
- 当你构建多个 web component 时,--name 将会用于设置前缀,同时自定义元素的名称会由组件的文件名推导得出。比如一个名为 HelloWorld.vue 的组件携带 --name foo 将会生成的自定义元素名为 <
vue-cli-service build --target wc --name foo 'src/components/*.vue'
异步 Web Components 组件
- 异步 Web Components 模式会生成一个 code-split(代码分割) 的包,带一个只提供所有组件共享的运行时,并预先注册所有的自定义组件小入口文件。一个组件真正的实现只会在页面中用到自定义元素相应的一个实例时按需获取:
vue-cli-service build --target wc-async --name foo 'src/components/*.vue' dist/foo.0.min.js dist/foo.min.js dist/foo.1.min.js dist/foo.js dist/foo.0.js dist/foo.1.js
————————————————————————————————————————————————————————————
部署
通用指南
本地预览
使用 history.pushState 的路由
CORS
PWA
Platform Guides
GitHub Pages
GitLab Pages
Netlify
Amazon S3
Firebase
Now
Stdlib
Heroku
Surge
Bitbucket Cloud
- 它们还会使用 让浏览器优先加载模块