15

I have a vue project created with vue-cli. The normal output when running yarn build is a dist folder with an index.html and a js and css sub-directory with the corresponding .js and .css files.

I want the build output to be a single html file that contains the js and css.

I added a vue.config.js file in the root of my project and set it to output a single js file and that is working ok. But I want to only have a single html file with the js and any css already on the html file.

module.exports = {
    css: {
        extract: false,
    },
    configureWebpack: {
      optimization: {
        splitChunks: false
      }
    }
  }

Basically I want my html file to be something like this:

<html lang=en>
    <head>
        ... meta tags
        <title>my title</title>
    </head>
    <body>
        <div id=app></div>
        <script>
           // contents of the output js file here
        </script>
    </body>
</html>

Is this possible?

Using Vue 3.9.3

Ju66ernaut
  • 2,592
  • 3
  • 23
  • 36
  • Could you describe your use case/scenario? I'm just curious, why you would do that – ssc-hrep3 Oct 07 '19 at 20:00
  • 3
    long story short, the document needs to be 100% standalone and offline ready to be downloaded and stored as a web view in an old (v1) cordova application – Ju66ernaut Oct 09 '19 at 15:21

1 Answers1

22

Someone answered with a suggestion to look into html-webpack-inline-source-plugin but removed their answer. But that was exactly what I needed to get this done.

The plugin is not Vue or Vue-CLI specific but it works if you do the following:

1) Add a vue.config.js file in the root of the app.

2) The linked plugin above is actually an extension of another package. You need both.

npm install --save-dev html-webpack-plugin 
npm install --save-dev html-webpack-inline-source-plugin 

3)

// vue.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
module.exports = {
    css: {
        extract: false,
    },
    configureWebpack: {
      optimization: {
        splitChunks: false // makes there only be 1 js file - leftover from earlier attempts but doesn't hurt
      },
      plugins: [
        new HtmlWebpackPlugin({
          filename: 'output.html', // the output file name that will be created
          template: 'src/output-template.html', // this is important - a template file to use for insertion
          inlineSource: '.(js|css)$' // embed all javascript and css inline
        }),
        new HtmlWebpackInlineSourcePlugin()
      ]
    }
  }

4) Add a template. This is necessary for working in the Vue context because without this the output html file by default won't have the necessary <div id="app"></div> and Vue won't mount to anything. I basically took the normal output html file and modified it a little.

<!-- output-template.html -->
<!DOCTYPE html>
<html lang=en>
    <head>
        <meta charset=utf-8>
        <meta http-equiv=X-UA-Compatible content="IE=edge">
        <meta name=viewport content="width=device-width,initial-scale=1">        
        <title>example title</title>
    </head>
    <body><noscript><strong>We're sorry but my example doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript>
        <div id=app>

        </div>
        <!-- plugin will insert js here by default -->
    </body>
</html>

Then build like normal and the output.html file will be in the /dist folder

Ju66ernaut
  • 2,592
  • 3
  • 23
  • 36
  • 3
    For this to work today I had to instead `npm install --save-dev html-webpack-inline-source-plugin@beta` and initialize the inline source plugin as `new HtmlWebpackInlineSourcePlugin(HtmlWebpackPlugin)` – matth Oct 10 '20 at 20:49
  • Is there any way to make this work for a MPA to separate the two pages? – Orestis Kapar Jan 14 '21 at 20:04
  • My experience from today is the same as matth's above. Using vue-cli UI, installed html-webpack-plugin 4.5.1 and manually html-webpack-inline-source-plugin@beta. – vess Jan 31 '21 at 13:23
  • 4
    How did you install html-webpack-plugin 4.5.1 via vue-cli UI? I can only select the latest and with that the build breaks with `Cannot read property 'tap' of undefined` – user2084865 Feb 10 '21 at 03:31
  • 2
    And with installing 4.5.1 via `npm i` I get `Cannot read property 'getHooks' of undefined` failing from html-webpack-inline-source-plugin. – user2084865 Feb 10 '21 at 03:33
  • 1
    Maybe it's a bit late, but i'm still documenting this for others: if u get the `Cannot read property 'getHooks' of undefined` message, you forgot to initialize the plugin as `new HtmlWebpackInlineSourcePlugin(HtmlWebpackPlugin)` in the vue.config.js plugins array. Adding that solved the problem. – sehe Oct 25 '21 at 09:00
  • 2
    When you get `'tap' of undefined`, you are probably using Webpack 4 with HtmlWebpackPlugin 5. Downgrade the latter to 4 and it works. – phil294 Nov 07 '21 at 14:50