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

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

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

1.vue组件install

js 复制代码
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打包组件

js 复制代码
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']
    })
  ]
};

打包入口与输出

js 复制代码
// 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的文件必须全部在项目目录下。

js 复制代码
  import(customUrl).then((comp) => {
          app.use(comp.default);
        });

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

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

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

js 复制代码
//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组件,但是不知道为什么这个子组件不解析

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

结果还是这样没解析

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

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

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

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

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

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

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

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

js 复制代码
import * as Vue from 'vue';
 window.vue = Vue;

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

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

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

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

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

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

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

谨记!

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

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

相关推荐
JUNAI_Strive_ving4 分钟前
番茄小说逆向爬取
javascript·python
看到请催我学习13 分钟前
如何实现两个标签页之间的通信
javascript·css·typescript·node.js·html5
twins352033 分钟前
解决Vue应用中遇到路由刷新后出现 404 错误
前端·javascript·vue.js
qiyi.sky1 小时前
JavaWeb——Vue组件库Element(3/6):常见组件:Dialog对话框、Form表单(介绍、使用、实际效果)
前端·javascript·vue.js
煸橙干儿~~1 小时前
分析JS Crash(进程崩溃)
java·前端·javascript
哪 吒1 小时前
华为OD机试 - 几何平均值最大子数(Python/JS/C/C++ 2024 E卷 200分)
javascript·python·华为od
安冬的码畜日常1 小时前
【D3.js in Action 3 精译_027】3.4 让 D3 数据适应屏幕(下)—— D3 分段比例尺的用法
前端·javascript·信息可视化·数据可视化·d3.js·d3比例尺·分段比例尺
l1x1n02 小时前
No.3 笔记 | Web安全基础:Web1.0 - 3.0 发展史
前端·http·html
Q_w77422 小时前
一个真实可用的登录界面!
javascript·mysql·php·html5·网站登录
昨天;明天。今天。2 小时前
案例-任务清单
前端·javascript·css