likes
comments
collection
share

记一次rollup打包远程vue组件的坑

作者站长头像
站长
· 阅读数 14

最近在搞BI仪表板重构项目,有个特殊的功能,要让用户可以上传自己开发的的组件,即远程组件。

远程组件的前提是要定好组件规范,数据,变量映射,全局配置(主题色,字体之类)的传入,以及暴露组件属性,表单配置项(有一套自动生成配置板面的form输入项),组件内动作触发时,抛出动作,定义事件数据规范,用于统一的交互处理。

1.vue组件install

import comp from './index.vue';

const components = [comp];
//注册组件,两种形式的组件名都注册aaa-bc,AaaBc
function install(Vue) {
  components.forEach((component) => {
    let item = component.name;
    if (component.name.indexOf('-') == -1) {
      let name = item.replace(/([A-Z])/g, (str, match) => {
        return '-' + match.toLowerCase();
      });
      name = name.substring(1);
      name = name.substring(0, 1).toLowerCase() + name.substring(1);
      Vue.component(name, component);
     
    } else {
      let name = item.replace(/-([a-z])/g, (str, match) => {
        return match.toUpperCase();
      });
      name = name.substring(0, 1).toUpperCase() + name.substring(1);
      Vue.component(name, component);
       
    }
    Vue.component(component.name, component);
  
  });
}

export default { install };

2.rollup打包组件

import json from '@rollup/plugin-json';

import vue from 'rollup-plugin-vue';
import scss from 'rollup-plugin-scss';
// import nodePolyfills from 'rollup-plugin-polyfill-node';
import { nodeResolve } from '@rollup/plugin-node-resolve';
// import filesize from 'rollup-plugin-filesize';
import postcss from 'rollup-plugin-postcss';
import postcssImport from 'postcss-import';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import terser from '@rollup/plugin-terser';
import strip from '@rollup/plugin-strip';
import replace from 'rollup-plugin-replace';
const env = process.env.NODE_ENV;
export default {
//外部引入vue
  external: ['vue'],

  plugins: [
    replace({
      'process.env.NODE_ENV': JSON.stringify(env)
    }),
    json(),
    // nodePolyfills(),
    nodeResolve(),
    scss(),
    babel({
      exclude: 'node_modules/**' // 只转译我们的源代码
    }),
    vue({
      css: true, // Dynamically inject css as a <style> tag
      compileTemplate: true // Explicitly convert template to render function
    }),
    postcss({
      extensions: ['.css', '.scss'],
      extract: true,
      plugins: [postcssImport()]
    }),

    commonjs({
      include: ['node_modules/**', 'node_modules/**/*']
    }),
    // 压缩代码
    terser(),
    // 剔除debugger、assert.equal和 console.log 类似的函数
    strip({
      labels: ['unittest']
    })
  ]
};

打包入口与输出

// rollup.config.js
import baseConfig from './rollup.base.config.js';
let compName = 'MyWorld';
export default {
  input: `./src/${compName}/index.js`,
  output: [
    {
      format: 'es',
      dir: 'dist/build/es'
    },
    {
      format: 'umd',
      dir: 'dist/build/umd',
       //vue用全局变量
      globals: {
        vue: 'vue'
      }, 
      name: compName
    }
  ],
  ...baseConfig
};

3.远程加载组件

vite有个奇怪的引入限制,vite会强制转换import的路径,导致引入错误,因此用import的文件必须全部在项目目录下。

  import(customUrl).then((comp) => {
          app.use(comp.default);
        });

记一次rollup打包远程vue组件的坑

记一次rollup打包远程vue组件的坑

当然有人会说用import.meta.glob动态路由,表示远程组件后面会放在服务器上,动态路由还是相对于当前项目目录的,还是走不通!

最终我放弃了用esmodule的import引入方式,改用了umd

很简单的创建一个script脚本元素,把src设为远程组件的地址,然后就ok了

//name组件名,customUrl远程组件地址
export function registerComp(name: string, customUrl: string) {
  return new Promise((resolve, reject) => {
    if (customUrl && !compMapping[name]) {
      try {
        let js = document.createElement('script');
        js.id = name;
        js.src = customUrl;
        js.onload = () => {
          compMapping[name] = 1;
          console.log(window[name]);
          app.use(window[name]);

          resolve(null);
        };
        js.onerror = (error) => {
          console.log(error);
          reject(null);
        };
        document.body.appendChild(js);
      } catch (error) {
        console.log(error);
        resolve(null);
      }
    } else {
      resolve(null);
    }
  });
}

然后成功将组件下载下来了,但新的问题来了!

4.打包的组件竟然子组件不解析

这是个二维码组件,引用了qrcode.vue组件,但是不知道为什么这个子组件不解析 记一次rollup打包远程vue组件的坑

我怀疑这个子组件没打包进去,然后自己写了个小组件引入

记一次rollup打包远程vue组件的坑

记一次rollup打包远程vue组件的坑

结果还是这样没解析

然后,临下班前,我又突发奇想弄一个没有子组件的组件,看看能不能渲染!

记一次rollup打包远程vue组件的坑

然后,我怀疑这个打包的组件是不是有问题,直接引入项目使用。

果不其然,也是没解析,说明这个组件本身就是有问题的。

啥情况?为什么别没这个问题,我就有这个问题?

然后我看了一下打包后的代码,我好像把vue打包进去了。

因为运行项目的vue跟组件里面的vue不是同一个vue,所以不解析子组件

然后问了搜索引擎,有人的博客说加了个external,globals,然后esmodule直接项目引入正常,但是远程umd失败了

然后看报错,说vue没有,然后加了个全局挂载的vue

import * as Vue from 'vue';
 window.vue = Vue;

还是不行?我人品问题吗?

问了我们组的大佬,大佬也没遇到过。

然后,大佬推荐问了AI,AI的回答没什么用

然后我找了好久,搞不定,大佬发话先不管,最终彻底摆烂,赶紧下班!

记一次rollup打包远程vue组件的坑

第二天早上脑袋清醒,回想了一下昨天找问题的全过程,仔细看了一下rollup配置文档,发现了华点。

我把globals的位置写错了,我直接放在了外面,这个东东应该放在output里面,然后没问题了~

//外部引入vue
  external: ['vue'],
  
  output:[
   {
      format: 'umd',
      dir: 'dist/build/umd',
       //vue用全局变量
      globals: {
        vue: 'vue'
      }, 
     
      name: compName
    }
 ]
  ...
  }

谨记!

别人的博客不一定写得很细致,该看官网还得看官网!

细节决定效率!唉~浪费了一天!

转载自:https://juejin.cn/post/7280831925332394019
评论
请登录