老项目平滑迁移 vue-cli3 日志

2,737 阅读5分钟

升级背景

公司项目是用 vue-cli 搭建的,至今已经有2年了热更新也越来越慢,正好 vue cli3 也出来,听说编译速度大大提升,就想把项目移植到 vue cli3

现状

技术: "webpack": "^3.6.0", "vue": "^2.5.2"

  1. 代码量越来越大,编译速度也越来越慢,打包时间快一分钟,热更新也越来越慢,影响开发效率
  2. 没有引入 eslint 语法检查, 代码风格不一
  3. webpack 配置繁琐
  4. 越来越多的UI库支持vue cli3

升级目的

  1. 提升编译速度
  2. vue cli3 创建项目时,引入 eslint,统一代码风格,方便代码 review(新手前端不想单独引入)
  3. 所有配置vue cli3 已经做了处理,额外配置在vue.config.js中处理即可
  4. 适应技术发展的潮流 🐶

项目升级

vue cl3 创建项目

vue create hello-world

详细步骤参考vue cli3文档

我用的配置是vue-router, vuex, less, babel, eslint

文件迁移

src 目录

简单粗暴把src移植过来,

复制src/pages,src/App.vue, src/index.html

复制src/main.js

报错:

控制台报错
main.js:121 Uncaught SyntaxError: Unexpected token !
    at Object../src/main.js (app.js:2481)
    at __webpack_require__ (app.js:770)
    at fn (app.js:130)
    at Object.1 (app.js:2555)
    at __webpack_require__ (app.js:770)
    at app.js:908
    at app.js:911

命令行报错
* cube-ui in ./src/main.js
* cube-ui/lib/picker/index.js in ./src/main.js
* cube-ui/lib/picker/picker.min.css in ./src/main.js
* cube-ui/lib/picker/picker.min.js in ./src/main.js
* cube-ui/lib/picker/style.css in ./src/main.js
* mint-ui in ./src/main.js
* mint-ui/lib/style.css in ./src/main.js
* vconsole in ./src/main.js
* vue-lazyload in ./src/main.js
* vue-resource in ./src/main.js

原因:没有引入第三方库和文件

解决:

  1. 引入对应的less文件和js文件
  2. 安装第三方库
npm i --save vue-resource vue-lazyload  mint-ui vconsole
  1. cube ui 引入 cube ui 在vue cli3中的引入方式和vue cli有所不同,具体步骤查看文档
vue add cube-ui

我这里是全局引入,因为原来的代码里也是全局引用的,其实应该按需引入的,这个等迁移工作完成后再优化,升级工作期间就不对业务代码做太大改动了

全局引入后,src目录会多一个cube-ui.js文件

  1. 此时重启服务后,报错
[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.

(found in <Root>)

原因:引入的vue.js版本和main.js里的写法不匹配

解决:修改main.js

// 原来
new Vue({
  el: '#app',
  router,
  store,
  template: '<App/>',
  components: { App }
})
// 修改
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')
  1. 成功编译

复制路由文件

vue cli的路由文件是放在 router 文件夹的, vue cli3 的路由在src/router.js, 我沿用vue cli的文件结构,依旧放在 router 文件夹里 引入路由文件后,报错:缺失components文件,接下来就

复制components文件夹

控制台疯狂报错,仔细看了下,有以下几种

  1. 文件名引入大小写问题
  2. 自定义指令文件, mixins文件还未引入
  3. 组件内引用的一些第三方库还没安装 npm i @chenfengyuan/vue-qrcode axios clipboard html2canvas particles.js swiper vue-awesome-swiper weixin-js-sdk --save
  4. less变量引用报错

解决:在vue.config.js引入全局less变量,参考vue cli3文档

const path = require('path')
module.exports = {
  chainWebpack: config => {
    const types = ['vue-modules', 'vue', 'normal-modules', 'normal']
    types.forEach(type =>
      addStyleResource(config.module.rule('less').oneOf(type))
    )
    config.plugins.delete('prefetch')
  },
  css: {
    loaderOptions: {
      stylus: {
        'resolve url': true,
        import: []
      }
    }
  },
  pluginOptions: {
    'cube-ui': {
      postCompile: true,
      theme: false
    }
  }
}

function addStyleResource (rule) {
  rule
    .use('style-resource')
    .loader('style-resources-loader')
    .options({
      patterns: [
        path.resolve(__dirname, 'src/assets/css/variable.less') // 需要全局导入的less
      ]
    })
}

jQuery引用

项目还用了jquery😭,用的地方还不少

解决:

  1. npm install jquery --save
  2. 检查下package.json看是否已经引入了
  3. .eslintrc.js 文件中,env 中 添加 jquery:true
  4. vue.config.js 添加插件
const webpack = require('webpack')
module.exports = {
  configureWebpack: {
    plugins: [
      new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        'windows.jQuery': 'jquery'
      })
    ]
  },
}
  1. main.js: import $ from 'jquery'

store文件引入

我的store文件是放在 store 文件夹的,迁移过去之后再更改main.js的引入路径即可

到这一步,项目基本就可以正常编译了,可以看到页面的基本轮廓,但还存在ui样式尺寸不对,请求跨域了等问题,依次解决

跨域

在vue.config.js中配置

  devServer: {
    port: 8080,
    proxy: {
      '/apis': {
        target: 'http://dev.xxx.com',
        changeOrigin: true,
        pathRewrite: {
          '/apis': ''
        }
      }
    }
  }

rem

修改 postcss.config.js

module.exports = {
  plugins: {
    autoprefixer: {},
    'postcss-px2rem': {
      remUnit: 75
    }
  }
}

好咯,到这一步,样式正常啦,请求也可以正常发送接收啦。

表面上看起来和正常的项目没什么区别了,可是一打开控制台,又看到一个报错..

vue-awesome-swiper

Swiper.vue?56a2:97 Uncaught (in promise) TypeError: _this.swiper.lockSwipes is not a function
    at eval (Swiper.vue?56a2:97)

是swiper插件的报错,上网找了下原因:swiper 新版本没有了lockSwipes这个api,替换成了 allowSlideNext

解决:

this.swiper.lockSwipes() 
// 替换成
this.swiper.allowSlideNext = false

某些地方的icon有点错位

排查了下原因是全局引入的 cube-ui 的默认样式引起的,在reset.less文件加了句

  body {
    line-height: initial;
  }

成功编译

至此为止,项目已经可以成功在 vue cli3 下跑起来啦。到处点一点,嗯,没什么报错了,接下来就来看看打包部分

打包

打包配置

原先的打包配置是在config/index.js

const path = require('path')

module.exports = {
  build: {
    // Template for index.html
    index: path.resolve(__dirname, '../dist/index.html'),
    // Paths
    // 输出静态资源路径
    assetsRoot: path.resolve(__dirname, '../../../../resource'),
    // 输出静态资源子目录
    assetsSubDirectory: 'static',
    assetsPublicPath: 'resource/',
  }
}

项目打包后生成的 index.html 和生成的静态资源的目录是不同的,而且打包好的html文件引用的静态资源路径得是相对路径(因为想开发测试生产都用一套代码)

在vue.config.js中的配置也需要修改:

{
  publicPath: process.env.NODE_ENV === 'production' ? './resource' : '/',
  indexPath: path.resolve(__dirname, 'dist/index.php'),//输出html目录
  outputDir: path.resolve(__dirname, '../../../resource'),// 静态资源目录
  assetsDir: 'static',// 静态资源子目录
}

vue cli3的文档只是很简单的提到publicPath,assetsDir.. 谷歌了半天,查了好久的资料,终于让我找到了答案😭

CSS minification error

配置完成, npm run build

报错:

CSS minification error: Cannot read property 'type' of undefined. File: css/doubleEleven.08c6b745.css

这个坑爹的报错,让我整整花了半天时间,这个报错的资料超少,最后是在vue cli3 的一个issue上看到了, 这个issue还因为提问不规范被关闭了,不过让我看到了条评论是说可能是transform:rotate()引起的。

虽然不知道为什么,我还是试了试查找了下项目代码,发现:

transform: rotate3d(0, 1, 00deg);

立马纠正,再次打包,打包成功,并且在开发,测试环境运行良好,耶️✌️

总结

😂升级的vue cli3后代码校验果真严格的好多,上面的错误在原来的编辑打包一点问题都没有,到这里就原形毕露了,不过总算完成了升级,在调试时明显感觉热更新速度提升了好多。

到此为止,这次的迁移工作就完成咯,当然还有些代码还得lint下或者手动修复下格式,这个就后续再做啦。