vue.jsvuejs3viterollupjs

How to Precompile Vue 3 Components using Vite and Use Them as JS Module in Static HTML?


I'm currently exploring Vue 3 with Vite for a project, and I'm aiming to optimize the loading time of my web application. My strategy involves precompiling Vue components and using them as JavaScript modules in static HTML files. However, I want to build these components one at a time, and I plan to pass the component path as a build argument.

Here are the specifics of what I'm trying to achieve:

  1. Precompile Vue 3 components: I want to optimize performance by precompiling Vue components.
  2. Utilize Vite for development and build processes: I aim to use Vite for its speed and efficiency.
  3. Build components one at a time: Instead of compiling all components at once, I want to build them individually.
  4. Pass component path as a build argument: The path to the component to be built should be passed as a build argument.

Despite researching Vue's documentation and Vite's documentation, I couldn't find a clear guide on how to implement this specific setup.

Could someone provide a step-by-step guide or point me to the right resources on how to precompile Vue 3 components using Vite, building them one at a time, and passing the component path as a build argument? I'm particularly interested in seamlessly incorporating these precompiled components as JavaScript modules in static HTML files.

Any help or guidance on this matter would be greatly appreciated. Thank you!


Solution

  • I was able to compile my Vue 3 SFCs using the following Vite configuration:

    import { defineConfig } from "vite";
    import vue from "@vitejs/plugin-vue";
    
    const parseComponentArg = () => {
      const arg =
        process.env.COMPONENT_ARG ||
        "default/path/to/your/component.vue:MyComponent"; // Default argument format
      const [path, name] = arg.split(":");
      return { path, name };
    };
    
    const { path: componentPath, name: componentName } = parseComponentArg();
    
    export default defineConfig({
      plugins: [vue({
        isProduction: true,
      })],
      build: {
        lib: {
          entry: componentPath, // Specify the path to your Vue component
          name: componentName, // Specify the name of your component library
          formats: ['umd']
        },
        rollupOptions: {
          external: ["vue", "lodash", "moment"], // Specify which modules are external
          output: {
            dir: componentPath.replace(/\/[^\/]+$/, ""), // Output directory (same directory as the source)
            entryFileNames: `${componentName}.js`, // Output file name
            globals: {
              vue: "Vue"
            },
          },
        },
      }
    });
    

    The HTML that I am progressively enhancing looks like this:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
      </head>
      <body>
        <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
        <script src="/components/HelloWorld/HelloWorld.js"></script>
    
        <div id="app">
            {{ message }}
            <hello-world />
        </div>
    
        <script>
          const { createApp } = Vue;
    
          const app = createApp({
            data() {
              return {
                message: "Hello Vue! From Vue 3 + Vite",
              };
            },
    
          });
          app.component("hello-world", HelloWorld);
          app.mount("#app");
    
        </script>
      </body>
    </html>
    

    Build Command for Vite:

    COMPONENT_ARG="./components/HelloWorld/HelloWorld.vue:HelloWorld" npm run build