目录
- 一、简介
- 二、实现过程
-
- 1. 配置打包指令(指定打包模式)
- 2. 定义模式行为
- 3. 定义打包逻辑
- 三、打包模式的应用
- 总结
一、简介
关于如何以及为什么要构建多页vue应用,我们在上一篇文章中已经介绍过,感兴趣的请参考构建多页vue应用。本文我们要介绍的是,对于一个多页应用,如何单独打包其中一个(或几个)页面。
一般来说,多页应用不需要打包单个页面,这多个页面可以作为整个应用直接放在静态资源服务器上。不过我们也说过,多页应用的每个页面也可能会放在不同的服务器上,这时候如果往每个服务器上都放置完整的资源包,就会显得过于臃肿。于是我们可能就需要将某个页面单独打包出来。
诚然,有一个很明显的方法,就是在每次打包的时候直接删掉
vue.config.js
的pages字段里不相关的页面,如:
module.exports = {
pages: {
page1: {...},
// page2: {...},
// page3: {...}
}
}
显然,这样打包出来的结果就是只有page1页面了。
但是每次打包都删改配置文件并不是一种很优雅的做法。我们需要的方案是有多个打包命令,执行对应的打包命令即可打包对应的页面,这样我们就可以不再改配置文件了。下面我们来介绍这种方法:
二、实现过程
要实现通过不同的打包命令来打包单独的页面,需要先从打包命令本身说起。
1. 配置打包指令(指定打包模式)
我们执行的打包命令为
npm run build
,这个命令执行的是
package.json
的
scripts
字段下的
build
命令,它的原始值如下:
{
...
"scripts": {
...
"build": "vue-cli-service build"
}
...
}
也就是说,这个命令实际上是在调用
vue-cli-service
服务的
build
命令。
根据vue-cli的文档介绍,build命令后面可以跟一个mode参数,定义打包模式,默认的打包模式包括
production
、
development
和
test
三个,它们的行为主要是把全局的
process.env.NODE_ENV
变量置为对应的值(即
production
、
development
和
test
)。在省略mode参数的情况下,默认值是
production
,即生产模式。
除了这三个默认模式外,我们还可以自定义打包模式。假如我们想定义一个专门打包page1的打包模式,就可以这样一个指令:
"scripts": {
"build-page1": "vue-cli-service build --mode page1"
}
我们希望,当执行
npm run build-page1
命令时,webpack就会自动把page1打包出来。
但显然只修改这里是不够的,webpack并不知道page1是什么模式,以及它应该有哪些行为。接下来我们需要为page1这个打包模式定义行为。
2. 定义模式行为
启用一个打包模式的本质含义,其实是启用一组特定的环境变量。
比如,
production
模式会把
process.env.NODE_ENV
的值置为
production
,而
process.env
是webpack所在的node环境提供的全局变量。这样,在代码中,只需要根据
process.env.NODE_ENV
的值就可以判断当前处于哪种打包模式了,代码可以根据不同的打包模式产生不同的行为。
对于自定义的打包模式,我们也可以指定一组全局变量,以使代码产生不同的行为。vue-cli文档规定,每个自定义模式对应的变量应该定义在根目录下的
.env.xxx
文件内。比如我们的打包模式名为
page1
,那么就需要在项目根目录下新建一个
.env.page1
(注意,这里是没有后缀的)文件:
当指定打包模式为
page1
时,webpack就会启用这个文件中所定义的变量。文件内可以这样定义变量:
.env.page1
NODE_ENV = 'production'
page = 'page1'
现在,当使用打包模式
page1
时,webpack就会读取这个环境文件,然后把这里定义的变量逐个添加到全局对象
process.env
上。因此此时
process.env.page
的值就是字符串
'page1'
(NODE_ENV的值需要在这里手动设置为
'production'
,否则会以开发模式打包)。
向全局变量注册了变量page之后,我们就可以在程序中根据它定义打包行为了。
3. 定义打包逻辑
之前我们定义多页应用的配置时,pages字段配置的是固定的值,也就是定义了三个打包入口。现在有了全局变量
process.env.page
,我们就不需要设为定值了,而是可以根据这个变量的值,动态定义打包入口。此时vue.config.js可以进行如下改造:
function resolvePages(page){
let page1 = {
entry: 'src/pages/page1/main.js',
template: 'public/index.html',
filename: 'page1.html',
};
let page2 = {
entry: 'src/pages/page2/main.js',
template: 'public/index.html',
filename: 'page2.html',
};
let page3 = {
entry: 'src/pages/page3/main.js',
template: 'public/index.html',
filename: 'page3.html',
};
return page === 'page1' ? { page1 } :
{ page1, page2, page3 };
}
module.exports = {
pages: resolvePages(process.env.page),
}
我们现在读取
process.env.page
的值进行判断,如果它的值是
page1
,那么说明我们处于
page1
打包模式下,于是resolvePages函数返回的对象仅包括
page1
这一个页面的入口,否则就返回三个打包入口,进行完整多页应用的构建。
基于这个原理,我们同样可以定义
page2
、
page3
的打包模式,甚至定义更加复杂的打包模式(如同时打包
page1
和
page2
),此时resolvePages函数的返回值只是稍微复杂一些:
return page === 'page1' ? { page1 } :
page === 'page2' ? { page2 } :
page === 'page1,page2' ? { page1, page2 } :
...
{ page1, page2, page3 };
现在一切准备就绪。
我们执行
npm run build-page1
命令时,vue-cli会先读取指定的
page1
模式对应的
.env.page1
文件,它会为
process.env
新增环境变量
page
。然后vue-cli会去读取
vue.config.js
配置文件中的pages字段,调用resolvePages函数,并传入变量
process.env.page
,得到打包入口对象为:
{ page1 }
,由于只有一个打包入口,因此vue-cli会调用webpack的打包服务,对该页面进行单独构建。
有人可能会问,难道只有打包时才能指定mode吗?其实不是的,
serve
命令也有mode参数。根据以上过程,你也可以单独启动某一个页面,此时你只需要定义下面这样的脚本:
{
...
"scripts": {
"serve-page1": "vue-cli-service serve --mode page1"
}
}
与打包过程没有什么差别,这里就不再赘述了。
需要注意的是,public文件夹下的资源是静态资源,无论使用任何打包模式,它们都会被直接拷贝到dist文件夹下。
三、打包模式的应用
打包模式的应用不仅在于单页打包,我们举一个更常见的例子:假设我们的代码打包后可能被派发到多个项目上,而这些项目之间却存在一些细小的差别(比如某个表格的样式不同)。如果我们为每个项目都单独创建一份代码,那么代码库将变得极难维护。这时候,打包模式就可以派上用场了。
我们可以为这些项目分别创建单独的打包命令,如:
{
"scripts": {
"build-project1": "vue-cli-service build --mode project1",
"build-project2": "vue-cli-service build --mode project2",
}
}
然后在根目录下分别为每个打包模式定义一个环境文件:
.env.project1
,
.env.project2
。我们在这里分别定义一组全局变量:
.env.project1
.env.project2
这里需要强调的是,如果需要在src路径下的代码中引用env中的某个变量,那么这个变量必须以
VUE_APP_
开头,否则结果都会是undefined(在src之外的代码中没有这个限制,如上面我们在vue.config.js中引用的变量就没有遵循这个约束,当然你可以更规范地对所有自定义变量添加这个前缀,以防止出错)。
现在,当执行
npm run build-project1
时,
process.env.VUE_APP_PROJECT
的值就是
project1
,我们可以在代码中根据这个值来区分不同的项目。比如在某个组件中,我们需要对项目1添加一些额外的逻辑:
methods: {
doSomething(){
if(process.env.VUE_APP_PROJECT === 'project1'){
// 对project1项目添加额外的逻辑
...
}
}
}
当你运行
npm run build-project1
打包命令时,if语句的内容就会生效,反之,在其他模式下,它不会生效。同样的,你也可以配置项目1专属的启动命令:
你可以运行
npm run serve-project1
来启用project1环境。
总结
通过学习在多页应用中打包单个页面,我们学会了如何自定义打包模式,这应该是本文最重要的知识点。将打包模式推广,我们学会了如何在一份代码中添加多个项目的逻辑,这使得我们维护多个项目分支的成本大大降低。打包模式的用途可能还远不止这些,希望读者理解它,并熟练运用。