javascriptvue.jswebpackblogger

Bundle Vue project into a single html file that can be embedded into a Blogger blogspot post


I want to bundle all the Vue.js project files (HTML, js, CSS) into a single HTML file so that it can be deployed in a blogger blogspot post.

A similar question was asked in the past for a ghost blog but it was about bundling the files into a single js file.

Bundle Vue project into single js file that can be embedded in Ghost blog post

I am using @vue/cli 5.0.1, yarn v1.22.21


Solution

  • To generate a single HTML file with embedded JS, CSS, images you can use the HTML Bundler Plugin for Webpack. This plugin can inline assets into HTML.

    For example, there is a simple Vue app including SCSS, TS and image files:

    index.html

    <!doctype html>
    <html lang="en">
      <head>
        <!-- source icon file -->
        <link href="./favicon.ico" rel="icon" />
        <!-- source style file -->
        <link href="./main.scss" rel="stylesheet" />
        <title>Vue</title>
      </head>
      <body>
        <div id="app">
          <h1>{{ title }}</h1>
          <!-- source image file -->
          <img src="./picture.png" />
          <my-button></my-button>
        </div>
        <!-- source TS file -->
        <script src="./index.ts"></script>
      </body>
    </html>
    

    index.ts

    import { createApp, ref } from 'vue';
    import MyButton from './MyButton.vue';
    import './styles.scss';
    
    createApp({
      setup() {
        return {
          title: ref('Hello Vue!'),
        };
      },
    })
      .component('my-button', MyButton)
      .mount('#app');
    

    MyButton.vue

    <template>
      <button>{{ text }}</button>
    </template>
    
    <script setup>
      import { ref } from 'vue';
      const text = ref('Button');
    </script>
    
    <!-- source style file -->
    <style src="./MyButton.scss" lang="scss"></style>
    

    simple Webpack config:

    const path = require('path');
    const { VueLoaderPlugin } = require('vue-loader');
    const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');
    
    module.exports = {
      mode: 'production',
      output: {
        path: path.join(__dirname, 'dist/'),
      },
      resolve: {
        alias: {
          vue: 'vue/dist/vue.esm-bundler',
        },
        extensions: ['.ts', '...'],
      },
      plugins: [
        new VueLoaderPlugin(),
        new HtmlBundlerPlugin({
          entry: {
            // define HTML templates here
            index: './src/views/index.html', // => dist/index.html
          },
          js: {
            // output JS filename, used only if the `inline` option is false
            filename: '[name].[contenthash:8].js',
            inline: true, // inline JS into HTML
          },
          css: {
            // output CSS filename, used only if the `inline` option is false
            filename: '[name].[contenthash:8].css',
            inline: true, // inline CSS into HTML
          },
          minify: 'auto', // minify html in production mode only
        }),
      ],
    
      module: {
        rules: [
          {
            test: /\.vue$/i,
            use: ['vue-loader'],
          },
          {
            test: /\.(css|scss)$/,
            use: ['css-loader', 'sass-loader'],
          },
          {
            test: /\.(ico|png|jp?g|svg)$/,
            type: 'asset/inline', // inline all images into HTML/CSS
          },
        ],
      },
    };
    

    The generated HTML file dist/index.html will be looks like:

    <!doctype html><html lang="en"><head><meta charset="UTF-8"/>
    <link href="data:image/vnd.microsoft.icon;base64,iVBORw0KGg..." rel="icon"/>
    <style>...embedded CSS...</style><title>Vue</title></head>
    <body><div id="app"><h1>{{ title }}</h1>
    <img src="data:image/png;base64,iVBORw0KGgoA..."/><my-button></my-button></div>
    <script>...embedded JS...</script></body></html>
    

    The compiled CSS, JS and images will be inlined in generated HTML.

    View the working example in browser on StackBlitz

    View complete source code on GitHub