Skip to content

feature request: support multiple configurations with one HTML file. eg type=module. #782

Closed

Description

@graingert

Description

support multiple configurations with one HTML file. eg <script type=module>

Specifically I'd like to create a config with babel loader set to:

{
  "presets": [
    ["env", {
      "targets": {
        "chrome": 61, "safari": "10.2"
      }
    }]
  ]
}

and one with babel loader set to:

{
  "presets": [
    ["env", {
      "targets": {
        "ie": 11
      }
    }]
  ]
}

then render both entry points in the same page with:

<script type="module" src="<- config[0].entry.js ->"><script>
<script nomodule src="<- config[1].entry.js ->"><script>

Activity

  1. mike-engel commented on Sep 19, 2017

    @mike-engel

    This would be awesome! I think it's important to keep it open to accepting multiple script sources. In my build, for example, three script tags get added because of code splitting:

    <script type="text/javascript" src="/runtime.d4c01c143617f5833c44.js"></script>
    <script type="text/javascript" src="/vendor.54efa82295fbe6e5beca.js"></script>
    <script type="text/javascript" src="/main.cd860d906240d47980f6.js"></script>

    So I guess the solution there would be something like (obviously I'm somewhat making up the syntax here):

    <- config[0].output.map(src => `<script type="module" src="${src}></script>`) ->
    <- config[1].output.map(src => `<script nomodule src="${src}></script>`) ->
    
  2. mastilver commented on Sep 21, 2017

    @mastilver
    Collaborator

    I'm all in for a multiple config setup: #780 (comment)

    Can put down the api you had in mind? (ie: which options would you pass down to new HtmlPlugin())

  3. mike-engel commented on Sep 21, 2017

    @mike-engel

    @mastilver That's a really good question! I don't think this can work unless there's a shared cache 😞. Here's how I ended up hacking this together for our (specific) webpack config. It was complicated a bit by us emitting several modules instead of a single main.js or bundle.js. This also doesn't really handle all CSS cases (it worked for our single CSS bundle).

    let sharedAssets = { chunks: {}, js: [] }
    
    function HtmlMultiBuildWebpackPlugin() {}
    
    HtmlMultiBuildWebpackPlugin.prototype.apply = function(compiler) {
      compiler.plugin('compilation', function(compilation) {
        compilation.plugin('html-webpack-plugin-before-html-processing', function(data, cb) {
          // Avoid chunk name collisions, since they can be named the same between builds
          // { 'main': {} } to { 'main-modern': {} } if the filename matches
          const obj = mapKeys(data.assets.chunks, (v, k) => {
            if (v.entry.includes('-modern')) { return `${k}-modern` }
    
            return k
          })
    
          sharedAssets.js = uniq(concat(sharedAssets.js, data.assets.js))
          sharedAssets.chunks = merge(sharedAssets.chunks, obj)
    
          const newData = merge(data.assets, sharedAssets)
    
          cb(null, newData)
        })
    
        compilation.plugin('html-webpack-plugin-alter-asset-tags', function(args, cb) {
          const newBody = args.body.map((arg) => {
            if (arg.attributes.src.includes('-modern')) {
              return merge(arg, {
                attributes: { type: 'module' }
              })
            } else {
              return merge(arg, {
                attributes: { nomodule: true }
              })
            }
          })
    
          cb(null, merge(args, { body: newBody }))
        })
      })
    }

    So I guess an api to accommodate that would look something like this? It's definitely weird!

    new HtmlWebpackPlugin({
      multiBuild: {
        cacheName: 'unique-name', // used to cache all chunks that go together
        suffixes: ['-modern'], // list of suffixes to watch out for. Could just be a string
        attributes: { // attributes to append based on the suffixes above. Would NEED to match
          '-modern': { type: 'module' }, // attribute overrides for the modern files
          default: { nomodule: true } // attribute overrides for everything else
        }
      }
    })
  4. robatwilliams commented on Dec 3, 2017

    @robatwilliams

    I tried out @mike-engel 's plugin from above - it works great.

    I created a gist with a few tweaks (functionally pretty much the same), and an usage example.

    What use cases are there for making this more generic than the scenario described in the opening post?

  5. stale commented on Jun 1, 2018

    @stale

    This issue had no activity for at least half a year. It's subject to automatic issue closing if there is no activity in the next 15 days.

  6. alexparish commented on Jun 11, 2018

    @alexparish

    Is there still appetite for this?

  7. firsttris commented on Jul 4, 2018

    @firsttris

    created a small plugin for html-webpack-plugin for webpack4 multi-build configuration which also support FF, IE11, Edge, Chrome, Safari 11.
    wrote down my findings...
    https://github.com/firsttris/html-webpack-multi-build-plugin

  8. housseindjirdeh commented on Oct 4, 2018

    @housseindjirdeh

    Just wanted to add my 2 cents here. I agree with @graingert in that using module/nomodule can help developers trim their bundle sizes by quite a bit (and Babel makes this transpilation process even easier with the esmodules target).

    It's so great to see plugins and workarounds created to solve this problem (such as the many already linked in this thread 🎉), but it would be awesome to have this supported by HTMLWebpackPlugin. Happy to help where possible!

  9. locked as resolved and limited conversation to collaborators on Nov 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions