jaketrent / html-webpack-template

a better default template for html-webpack-plugin
MIT License
830 stars 139 forks source link

inlineManifestWebpackName not working #75

Closed pldg closed 6 years ago

pldg commented 6 years ago

I try to inline webpack manifest but with the following config is not working:

module.exports = {
  optimization: {
    runtimeChunk: { name: 'runtime' }
  },
  plugins: [
    new HtmlWebpackPlugin({
      inject: false,
      template: require('html-webpack-template'),
      inlineManifestWebpackName: 'runtime'
    }),
    new InlineManifestWebpackPlugin()
  ]
};

Note: 'runtime' is the default name for webpack manifest.

My devDependencies versions:

"html-webpack-plugin": "^3.2.0",
"html-webpack-template": "^6.2.0",
"inline-manifest-webpack-plugin": "^4.0.0",
"webpack": "^4.10.1"

What's happen

Looking inside html-webpack-template.ejs I see:

<% if (htmlWebpackPlugin.options.inlineManifestWebpackName) { %>
  <%= htmlWebpackPlugin.files[htmlWebpackPlugin.options.inlineManifestWebpackName] %>
<% } %>

Logging htmlWebpackPlugin.files, there is no plain manifest code inside this object but only a reference to 'runtime' chunk.

Solution

We can use the compilation object and add the following code to the template:

<% const webpackManifestName = htmlWebpackPlugin.options.inlineManifestWebpackName ? 
new RegExp(htmlWebpackPlugin.options.inlineManifestWebpackName, 'g') : '' %>
<% if (webpackManifestName) { %>
    <script type="text/javascript">
      <% const webpackManifest = htmlWebpackPlugin.files.js
      .filter( file => file.match(webpackManifestName) ); %>

      <%= compilation.assets[webpackManifest].source() %>
    </script>
<% } %>
<% Object.keys(htmlWebpackPlugin.files.chunks)
  .filter(chunk => webpackManifestName ? !chunk.match(webpackManifestName) : chunk)
  .forEach(chunk => {
    if (htmlWebpackPlugin.files.jsIntegrity) { %>
      <script
        src="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"
        type="text/javascript"
        integrity="<%= htmlWebpackPlugin.files.jsIntegrity[htmlWebpackPlugin.files.js.indexOf(htmlWebpackPlugin.files.chunks[chunk].entry)] %>"
        crossorigin="<%= webpackConfig.output.crossOriginLoading %>">
      </script>
    <% } else { %>
      <script src="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>" type="text/javascript"></script>
    <% } %>
<% }) %>

Note: InlineManifestWebpackPlugin is not strictly necessary, in this case it's used to delete runtime.js chunk in the dist/ folder.

rmunch commented 6 years ago

I ran into this issue as well - @pldg 's solution worked with one alteration to support Webpack's publicPath config.

<% if (webpackManifestName) { %>
<script type="text/javascript">
    <% const webpackManifest = htmlWebpackPlugin.files.js
        .filter( file => file.match(webpackManifestName) )[0]
        .replace(webpackConfig.output.publicPath, '') %>

    <%= compilation.assets[webpackManifest].source() %>
</script>
<% } %>
pldg commented 6 years ago

Would be nice a solution that works without adding InlineManifestWebpackPlugin to delete dist/runtime.js but for now I'm closing this issue.