rollup打包vue虚拟组件

41 阅读1分钟

rollup打包vue虚拟组件

为了实现在线版的vitepress将md文件内容转为html,并且提供vue支持,可以在md中编写或引入vue并展示。所以需要实现rollup打包vue虚拟组件的功能。

具体步骤:md文件=》html字符串 =》 vue文件 =》 rollup打包 =》 js代码 实现

将md文件渲染为html字符串

使用markdown-it实现转换 例如:

<script lang="ts" setup>
import MyButton from '@/compoent/Button.vue'
const content = 'pageContent ...'
</script>

# title
## subTitle
{{content}}

<MyButton>submit</MyButton>
<script lang="ts" setup>
import MyButton from '@/compoent/Button.vue'
const content = 'pageContent ...'
</script>
<h1>title</h1>
<h2>subTitle</h2>
<p>{{content}}</p>

<MyButton>submit</MyButton>

将虚拟vue文件变为js代码

<script lang="ts" setup>
import MyButton from '@/compoent/Button.vue'
const content = 'pageContent ...'
</script>
<template>
  <div>
    <h1>title</h1>
    <h2>subTitle</h2>
    <p>{{content}}</p>

    <MyButton>submit</MyButton>
  </div>
</template>
<h1>title</h1>
<h2>subTitle</h2>
<p>pageContent ...</p>
<button class="mybutton">submit</button>

rollup打包配置

目标是一个支持severless,一件部署的文档工具。 由于要支持severless所以,不支持写文件,要使用memfs库实现在内存中读写文件。

const vol = Volume.fromJSON({
  "virtual.vue": str,// 虚拟vue组件代码
});
const fsVol = createFsFromVolume(vol);
const myfs = {
  promises: {
    readFile: (filePath: string, options?: any) => {
      if (filePath === "virtual.vue")
        return fsVol.promises.readFile(filePath, options);
      else return fs.promises.readFile(filePath, options);
    }
  },
};

const bundle = await rollup({
  input: ["virtual.vue"],
  //@ts-ignore
  fs: myfs.promises,
  external: ["vue"],
  plugins: [
    vue({
      preprocessStyles: true,
    }),
    postcss({
      inject: true,
    }),
    nodeResolve({
      extensions:['.js','.ts','.vue']
    }),
    commonjs(),
    esbuild({
      target: "es2022",
      optimizeDeps: {
        esbuildOptions: {},
        include: [],
      },
      sourceMap: false,
      loaders: {
        ".vue": "ts",
      },
    }),
  ],
});
const { output } = await bundle.generate({format:'esm'})
console.log("output[0].code: ",output[0].code);

打包后效果

import { defineComponent, createElementBlock, openBlock, createElementVNode, createVNode } from 'vue';

var script = /* @__PURE__ */ defineComponent({
  __name: "virtual",
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", null, [
        _cache[0] || (_cache[0] = createElementVNode(
          "h1",
          null,
          "test1",
          -1
          /* CACHED */
        )),
        createVNode(script$1, { name: "more" })
      ]);
    };
  }
});

script.__file = "virtual.vue";

export { script as default };

这样就支持在浏览器端import并且使用了