记一次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
    }
 ]
  ...
  }

谨记!

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

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

相关推荐
xing25162 分钟前
pytest-html
前端·html·pytest
茂茂在长安12 分钟前
Linux 命令大全完整版(11)
java·linux·运维·服务器·前端·centos
Violet51513 分钟前
ECMAScript规范解读——this的判定
javascript
知识分享小能手1 小时前
Html5学习教程,从入门到精通,HTML5 简介语法知识点及案例代码(1)
开发语言·前端·javascript·学习·前端框架·html·html5
IT、木易1 小时前
大白话React第二章深入理解阶段
前端·javascript·react.js
晚安7201 小时前
Ajax相关
前端·javascript·ajax
图书馆钉子户1 小时前
怎么使用ajax实现局部刷新
前端·ajax·okhttp
bin91531 小时前
DeepSeek 助力 Vue 开发:打造丝滑的单选按钮(Radio Button)
前端·javascript·vue.js·ecmascript·deepseek
qianmoQ1 小时前
第五章:工程化实践 - 第五节 - Tailwind CSS 常见问题解决方案
前端·css
那就可爱多一点点1 小时前
超高清大图渲染性能优化实战:从页面卡死到流畅加载
前端·javascript·性能优化