ziyi2 / ziyi2.github.io

www.ziyi2.cn
53 stars 5 forks source link

VUE CLI3缓存旧版本的VUE组件(npm包)问题 #2

Open ziyi2 opened 5 years ago

ziyi2 commented 5 years ago

发现问题

在使用VUE CLI3生成项目时,引入未打包的组件(这里的组件发布成了npm包,抛出的仍然是原生态的.vue文件,由于该组件采用VUE CLI3调试和生成,且目标环境是VUE CLI3,因此组件可以和VUE CLI3业务代码完美契合,同时也可以防止二次打包问题,当然有使用一些VUE CLI3不包含的特殊webpack loader的VUE组件仍然是推荐打包后发布),发现组件的版本更新后,启动项目显示的仍然是旧版本的组件

组件(npm包)结构

├── packages             
│   └── xxx
│      ├── src                 
│      │  └── xxx.vue       
│      ├── theme                 
│      │  └── index.scss      
│      ├── index.js                
│      └── package.json 

package.json中的main字段指向了index.js

VUE CLI项目中引入

// src/main.js
import xxx from 'xxx'
import 'xxx/theme/index.scss'

Vue.use(xxx)

定位问题

第一反应是与缓存相关,于是使用VUE CLI3/开发/webpack相关/审查项目的 webpack 配置中的vue inspect功能输出了当前项目的Webpack配置,寻找出与cache-loader相关的配置信息:

 /* config.module.rule('vue') */
 {
   test: /\.vue$/,
   use: [
     /* config.module.rule('vue').use('cache-loader') */
     {
       loader: 'cache-loader',
       options: {
         cacheDirectory: 'G:\\dolphin-vuc-cli3\\dolphin_issc\\node_modules\\.cache\\vue-loader',
         cacheIdentifier: 'b466c286'
       }
     },
     /* config.module.rule('vue').use('vue-loader') */
     {
       loader: 'vue-loader',
       options: {
         compilerOptions: {
           preserveWhitespace: false
         },
         cacheDirectory: 'G:\\dolphin-vuc-cli3\\dolphin_issc\\node_modules\\.cache\\vue-loader',
         cacheIdentifier: 'b466c286'
       }
     }
   ]
 },

/* config.module.rule('js') */
{
   test: /\.m?jsx?$/,
   exclude: [
     function () { /* omitted long function */ }
   ],
   use: [
     /* config.module.rule('js').use('cache-loader') */
     {
       loader: 'cache-loader',
       options: {
         cacheDirectory: 'G:\\dolphin-vuc-cli3\\dolphin_issc\\node_modules\\.cache\\babel-loader',
         cacheIdentifier: 'b77d1c56'
       }
     },
     /* config.module.rule('js').use('babel-loader') */
     {
       loader: 'babel-loader'
     }
   ]
 },

发现cache-loader匹配了/\.vue$//\.m?jsx?$/文件,因此需要去除cache-loader并观察是否是该loader引起的问题。

更改webpack配置文件

由于VUE CLI3项目使用webpack-chain链式操作在源码中动态生成Webpack配置,因此有两种方式更改VUE CLI3项目的配置信息:

这里采用第二种方式进行验证,去除config.module.rule('vue')中的缓存配置:

// @vue/cli-service/lib/config/base.js
webpackConfig.module
 .rule('vue')
   .test(/\.vue$/)
   // .use('cache-loader')
   //   .loader('cache-loader')
   //   .options(vueLoaderCacheConfig)
   //   .end()
   .use('vue-loader')
     .loader('vue-loader')
     .options(Object.assign({
       compilerOptions: {
         preserveWhitespace: false
       }
     // 第一次尝试的时候没注释这里,只注释了cache-loader,导致问题一直排查不出来
     // 花费了两个晚上时间,代价有点大(因为第一次尝试就将vue-loader排除在外)
     // }, vueLoaderCacheConfig))
     }))

去除config.module.rule('js')中的缓存配置:

// @vue/cli-plugin-babel/index.js
const jsRule = webpackConfig.module
     .rule('js')
       .test(/\.m?jsx?$/)
       .exclude
         .add(filepath => {
           // always transpile js in vue files
           if (/\.vue\.jsx?$/.test(filepath)) {
             return false
           }
           // exclude dynamic entries from cli-service
           if (filepath.startsWith(cliServicePath)) {
             return true
           }

           // check if this is something the user explicitly wants to transpile
           if (transpileDepRegex && transpileDepRegex.test(filepath)) {
             return false
           }
           // Don't transpile node_modules
           return /node_modules/.test(filepath)
         })
         .end()
       // .use('cache-loader')
       //   .loader('cache-loader')
       //   .options(api.genCacheConfig('babel-loader', {
       //     '@babel/core': require('@babel/core/package.json').version,
       //     '@vue/babel-preset-app': require('@vue/babel-preset-app/package.json').version,
       //     'babel-loader': require('babel-loader/package.json').version,
       //     modern: !!process.env.VUE_CLI_MODERN_BUILD,
       //     browserslist: api.service.pkg.browserslist
       //   }, [
       //     'babel.config.js',
       //     '.browserslistrc'
       //   ]))
       //   .end()

更改源码后,验证发现是cache-loader引起的问题,缩小范围发现是vue-loader的缓存配置引起的问题。

结论

VUE CLI3缓存旧版本的VUE组件(npm包)是由于vue-loader中配置了缓存而引起的,并且发现VUE CLI3的 源码中并没有可以关闭该缓存的配置项,因此这里提供了以下解决方案:

1、对VUE CLI官方提出 issue ,等待官方解决该问题(目前仍然没有解决)。

2、如果需要更新组件版本,首先删除node_modules下的.cache文件,然后更新组件版本启动项目。

3、更给vue.config.js,去除config.module.rule('vue')中的缓存配置。

参考链接

ziyi2 commented 5 years ago

vue-loader会缓存node_modules中的npm包导致更新npm包后每次启动都是缓存中的版本问题 - Vue CLI Issue

ziyi2 commented 5 years ago

4