基于vue-cli的单页面开发配置

简述

基于最近一次使用cli构建一个单页面项目的细节和体会做一个总结,项目后台环境为php。其中的不足之处可以指出,相互学习。

一个完整项目从开始到上线需要的步骤分析

  1. 本地ui界面开发;
  2. 接口开发和联调;
  3. 项目测试问题处理;
  4. 项目上线;

项目开始时准备工作

由于是一个新项目,所以需要新建git仓库,并把初始的结构代码放入master分支,然后切出2个分支,一个是测试分支develop,一个项目分支time_project_branch

在项目开始界面开发前的首要工作便是配置好本地开发的环节,为了避免多人在统一分支开发引起的频繁冲突,所以基于time_project_branch又单独拉出了preson_project_branch作为个人开发分支。

接下来便开始进入操作,首先当然是初始化一个vue-cli项目,过程很简单

sudo vue init webpack my-project && cd my-project

接下来需要处理一些开发前需要处理的问题:

  • 包的锁定问题

安装完成后第一步便是关于依赖包的管理问题,在package.json文件中各种依赖包的安装方式为大于当前最低大版本即可,例如vue的包安装方式为"vue": "^2.5.17",,意思就是说2.x版本的vue中大于2.5.17就可以被安装。这对项目而言是很危险的,并且我们知道有一个package-lock.json文件可以用来锁定包版本,此时我们先安装一个必须的依赖axios,接着就可以看到在项目根目录下出现了这个lock文件,可是这并不是完全锁定的。查阅相关介绍可以发现package-lock.json文件相当于node_module文件的树结构,并且基于package.json生成,也允许用户使用符合package.json文件所需依赖的包文件,也就是说并不会直接根据lock文件依赖的包版本安装文件。同理,yarn安装方式下的yarn.lock文件也有这样的问题。所以我们便找到了npm-shrinkwrap.json文件,这个便是我们要的,它可以确保安装包的每个人都得到完全相同版本的所有依赖项,关于它的具体介绍可以看官方关于npm-shrinkwrap.json文件的介绍。

  • 编译后的代码的兼容问题

如果是原生开发,顺其自然便可想到,所谓的兼容无非就是html,css,js的兼容。反观cli方式下的开发方式,html会包裹在vue的template标签中,而内部的标签除了html外就是vue内置的一些例如:transition keep-alive之类的特殊功能标签,不难想到最后的页面依然是我们熟悉的html,从编译后的文件我们便不难看出,所以html是可以完全兼容的。

接下来是css,首先确定了项目使用的为less作为css开发方式,并且cli已经帮我们内置了关于less文件的处理,具体可以在build目录下的util.js中找到关于less的操作,我们只需要安装less即可,此时终端输入

sudo npm install less less-loader

便可在项目中使用less。但是由于css3在移动端的使用已经普及,并且不同浏览器的前缀cli已经提前预置,所以也不会产生兼容问题。

最后说到比较关键的问题,就是js。在不用构建工具的前提下,我们知道js在不同浏览器是有兼容问题的,所以才会有jquery之类的库的存在和普及,在cli项目中,虽然很少有直接的dom操作,但是es6的代码方式是必然的,如模块的引入和导出。所以babel作为编译es6+的构建工具,它的兼容性基本决定了js的兼容性。首先贴出最后的处理结果代码:

"presets": [
    ["env", {
        "modules": false,
        "targets": {
            "browsers": ["> 0.01%", "last 2 versions", "not ie <= 8"]
        }
    }],
    "stage-0"
]

cli默认的为

"presets": [
    ["env", {
        "modules": false,
        "targets": {
            "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
        }
    }],
    "stage-2"
]

首先说这里的stage-x代表的是对于一些es6+的草案的支持,其中stage-0包含了其他所有,所以最为保险。其次browsers参数列出了具体需要babel处理后兼容到哪种程度。除了这些,babel的参数配置可以支持更强大的配置方式,具体可以通过babel官网来解锁更多。

  • axios的处理

axios为一个纯粹xhr请求的第三方库,支持手工配置请求过程中的参数,第一步安装

npm install axios

由于axios通常需要在所有地方使用,所以需要在main.js中挂在到vue实例上,而axios本身我们可以通过create这个方法做相关拦截,具体配置方式可以参考npm上axios的介绍

这里说一下关于axios中post请求的配置方式,安装好axios后,默认会安装一个qs模块,这个模块可以用来处理post中的参数序列化问题,避免post请求报错。具体的处理方式为在axios的create中添加如下配置:

var instance = axios.create({
    ...
    transformRequest : [function (data) {
        data = Qs.stringify(data);
        return data;
    }],
    headers : {
        'Content-Type' : 'application/x-www-form-urlencoded',
    },
    ...
});

stringify方法会把json参数转化为url序列化的形式。这样就可以正常进行post请求了。

  • proxyTable本地代理

config下的indexdev配置下有proxyTable选项用来处理代理问题,为了方便统一管理,可以单独用一个js来写相关配置。这里有一个可以用来处理cookie相关的配置参数cookieDomainRewrite,具体可以查阅npm包http-proxy-middleware

  • rem处理

直接使用flexable放在构建模版里即可

  • 不同环境下的打包方式处理

项目有本地,测试和上线3个步骤,本地使用html文件作为构建模版,另外2个环境下使用php文件作为构建模版。以测试环境构建为例来说明下如何操作。

package.json里的scripts下增加

"test": "node build/test.js",

然后在对应位置增加一个test.js文件,由于cli本身有一个bulid选项,所以可以把build.js中的内容cv过来。在js头部声明当前环境为dev,代码为

process.env.NODE_ENV = 'test'

替换文件中webpack的构建配置为

const webpackConfig = require('./webpack.test.conf')

这里便算操作完成了。

同理,新建一个webpack.test.conf.js文件,内容cvwebpack.prod.conf.js。在config下新建一个test.env.js内容如下:

'use strict'
module.exports = {
  NODE_ENV: '"test"'
}

只用来输出一个变量NODE_ENV,并引入到webpack.test.conf.js中。更改所有config.build.xxxconfig.test.xxx,并把HtmlWebpackPlugin中的模版指向index.blade.php,如此test环境和config配置就都更改完毕了。只需更改config下的index.js文件便可完成(这也依赖于cli提供的结构,把配置和构建分开,方便操作和管理)。

找到config下的index.js文件,和build同级新加一个test,内容cvbuild内容。主要更改如下内容即可

    index: ..., // 构建后的模版位置
    assetsRoot: ..., // 构建后的目录位置和名字
    assetsSubDirectory: ..., // 构建后的资源目录名字
    assetsPublicPath: ..., // 构建后的资源地址

此时,运行npm run test便可以构建专属于test环境下的构建流程,当然webpack的具体处理细节可以在当前环境文件下自由操作。

  • 数据mock

数据mock采用了mockjs,理由是简单稳定方便。由于mock数据不会是最终的源码和构建后代码的一部分,并且最好可以不涉及对源码的更改来实现和真实数据的代码无缝切换,所以只需要处理dev环境即可。默认一种开发本地构建方式为npm run dev执行于后台对接的真实接口,npm run dev --mock执行本地mock数据。参考cli的结构思路,我们单独在build下新建了mock.config.js来处理关于mock的配置。最终代码如下:

const config = require('../config')
// mock配置
module.exports =  mockChuncks = (() => {
    const envArgs = JSON.parse(process.env.npm_config_argv).original;
    let mockConfig = {
        isMock: false,
        chuncks : ['app'],
        proxy : config.dev.proxyTable
    };
    if(envArgs.indexOf('--mock') !== -1) {
        mockConfig = {
            isMock: true,
            chuncks : ['mock', 'app'],
            proxy : {}
        }
    }
    return mockConfig;
})();

引入config下的index是为了处理代理问题,避免和mock数据产生冲突,envArgs变量用来获取用户终端输入。我们的思路是,如果不使用mock,则走代理配置,之前的操作不变,如果使用mock,则把mock数据在webpack的entryHtmlWebpackPluginchunks中引入,通过自定义的isMock来给其它配置文件传递是否需要mock的标示,并把webpack.dev.conf.js下的devServer.proxy置空。这么一看,便一眼望穿mock.config.js中的代码含义。剩下的只需在必要的地方使用即可。

项目在测试和线上环境的构建

首先,目前我们使用jenkins做为构建方式,具体操作文档可以自行官方。当本地开发完成后,代码为开发时的业务逻辑代码,所以我们需要jenkins做编译和分发代码的功能。以测试环境为例,一个新的jenkins项目操作方式如下:

  1. 新建一个自定义风格项目,并写入项目名;
  2. 在源码管理中选择git,并在Repository URL中写入git地址,在Credentials中加入获取git项目代码时需要的账户密码;
  3. Branches to build中写入需要构建的分支,此时为测试环境,所以写入我们约定好的测试分支名develop即可;
  4. 在构建中新增Execute shell来写入需要执行的命令,大体结构如下:
npm install
npm run test
rsync -alvr dist/templates/index.blade.php  真实测试地址模版目录
rsync -alvr dist/static  真实测试地址资源目录

5.点击保存,执行构建。

这样测试环境下的构建工作便完成了,这里有2点疑问

  • 为什么不用淘宝镜像

在实际过程中出现了使用淘宝镜像源安装失败的问题,原因大致为淘宝镜像版本不同步或和原npm包代码冲突。并且npm包在初次安装后,便会有_cacache的文件的产生来缓存下载包的相关内容,具体看npm cache。这样一来,除了首次会慢之外,在不引入新的数量比较多的npm包的前提下,install的速度也会很快。并且为了确保在使用中引入淘宝镜像的依赖包,在项目根目录下新建了.npmrc文件来强制安装时走npmjs官网,代码如下:

registry=http://registry.npmjs.org
  • 为什么不在本地构建,在jenkins上只做dist目录文件的转发

因为dist目录为生成目录,并不属于源代码范畴,而git是用来管理源代码的仓库。所以为了项目更清晰纯粹,选择在jenkins构建环节构建源代码。

总结

  1. vue-cli为开发者提供了一套开箱即用的开发方式,但是在具体公司和项目中需要简单对其处理。因为是新增逻辑,所以在确保不是负面影响原有逻辑的基础上,所加代码需要通过各种工具的官方文档,自测通过为前提进行改造,确保项目有条不紊的进行;
  2. 项目中代码有自己写入的原始代码,库(例如vue)封装的逻辑代码,第三方包引入的效果和打包逻辑处理工具。在开发代码层面,我们可以定制ui,交互方式,在构建过程我们可以定义源代码处理方式,构建打包方式等基于node的文件处理和编译过程。在各个阶段,采用耦合程度低,配置化的方式无疑是如鱼得水;
  3. 项目结构是为了更好的开发,所以需要在一开始便考虑好大体的思路,这样才能有条不紊的进行开发工作;

共勉~

发表评论