New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
graingert opened this Issue Sep 11, 2017 · 8 comments

Comments

Projects
None yet
8 participants
@graingert
Copy link
Contributor

graingert commented Sep 11, 2017

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>
@mike-engel

This comment has been minimized.

Copy link

mike-engel commented Sep 19, 2017

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>`) ->
@mastilver

This comment has been minimized.

Copy link
Collaborator

mastilver commented Sep 21, 2017

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())

@mike-engel

This comment has been minimized.

Copy link

mike-engel commented Sep 21, 2017

@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
    }
  }
})
@robatwilliams

This comment has been minimized.

Copy link

robatwilliams commented Dec 3, 2017

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?

@stale

This comment has been minimized.

Copy link

stale bot commented Jun 1, 2018

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.

@stale stale bot added the wontfix label Jun 1, 2018

@alexparish

This comment has been minimized.

Copy link

alexparish commented Jun 11, 2018

Is there still appetite for this?

@stale stale bot removed the wontfix label Jun 11, 2018

@firsttris

This comment has been minimized.

Copy link

firsttris commented Jul 4, 2018

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

@jantimon jantimon closed this Sep 14, 2018

@housseindjirdeh

This comment has been minimized.

Copy link

housseindjirdeh commented Oct 4, 2018

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!

@lock lock bot locked as resolved and limited conversation to collaborators Nov 3, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.