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

Code splitting #372

Closed
Rich-Harris opened this Issue Dec 22, 2015 · 65 comments

Comments

Projects
None yet
@Rich-Harris
Contributor

Rich-Harris commented Dec 22, 2015

Previously: #120.

Probably not going to happen any time soon, but at some point it would be nice to add support for code-splitting, i.e. finding the common dependencies of a.js and b.js so that you can do this sort of thing...

<!-- a.html -->
<script src='shared.js'></script>
<script src='a.js'></script>

<!-- b.html -->
<script src='shared.js'></script>
<script src='b.js'></script>

...and let visitors to b.html who have already been to a.html use a cached copy of shared.js (mutatis mutandis for client-side routing situations with an asynchronous module loader).

First hard question is what the API looks like – my initial thought is that if you specify x entry points you should get x+1 bundles back, where the +1 is the shared code. Very easy to grok and probably meets most use cases, but not as flexible as some other approaches.

Anyway I'll just leave this here for now.

@thisconnect

This comment has been minimized.

Show comment
Hide comment
@thisconnect

thisconnect Dec 22, 2015

I'd love to have control over what is shared. I.e b.html and c.html may share a large part, that I don't want to have in. I belive that people usually like to decide what should be shared and whatnot.

thisconnect commented Dec 22, 2015

I'd love to have control over what is shared. I.e b.html and c.html may share a large part, that I don't want to have in. I belive that people usually like to decide what should be shared and whatnot.

@Rich-Harris Rich-Harris added this to the future milestone Dec 30, 2015

@thisconnect

This comment has been minimized.

Show comment
Hide comment
@thisconnect

thisconnect Dec 31, 2015

Related to automatic finding common dependencies, I am currently trying to setup 2 configs to manually control what goes in the shared common lib and what goes into app.

  • app1.js
  • common/
    • index.js
    • moduleA.js
    • moduleB.js

Trying to keep it as simple as possible, my approach is currently to build 2 iife one as a lib and the app importing from the lib (common/index.js).

common/index.js

export * from './moduleA.js';
export * from './moduleB.js';

Is there a better way to export all shared modules, than listing all modules and export * from?

app1.js

import Lib from './common/index.js';

The lib build works fine (entry common/index.js, moduleName Lib),
but I can't find a way to exclude the Lib from app.

I am not sure if this approach should be working at all or if it would make sence to put all common code into its own node module, see #401

thisconnect commented Dec 31, 2015

Related to automatic finding common dependencies, I am currently trying to setup 2 configs to manually control what goes in the shared common lib and what goes into app.

  • app1.js
  • common/
    • index.js
    • moduleA.js
    • moduleB.js

Trying to keep it as simple as possible, my approach is currently to build 2 iife one as a lib and the app importing from the lib (common/index.js).

common/index.js

export * from './moduleA.js';
export * from './moduleB.js';

Is there a better way to export all shared modules, than listing all modules and export * from?

app1.js

import Lib from './common/index.js';

The lib build works fine (entry common/index.js, moduleName Lib),
but I can't find a way to exclude the Lib from app.

I am not sure if this approach should be working at all or if it would make sence to put all common code into its own node module, see #401

@Victorystick

This comment has been minimized.

Show comment
Hide comment
@Victorystick

Victorystick Dec 31, 2015

Member

common/index.js should probably export it's submodules' namespaces,

import * as moduleA from './moduleA.js';
import * as moduleB from './moduleB.js';

export { moduleA, moduleB };

And then in app1.js import,

import { moduleA, moduleB } from './common/index.js';

And hack together a plugin that will ensure that ./common/index.js isn't included in the bundle. I think that should be possible.

Member

Victorystick commented Dec 31, 2015

common/index.js should probably export it's submodules' namespaces,

import * as moduleA from './moduleA.js';
import * as moduleB from './moduleB.js';

export { moduleA, moduleB };

And then in app1.js import,

import { moduleA, moduleB } from './common/index.js';

And hack together a plugin that will ensure that ./common/index.js isn't included in the bundle. I think that should be possible.

@thisconnect

This comment has been minimized.

Show comment
Hide comment
@thisconnect

thisconnect Dec 31, 2015

Do you think that this approach is ok? One disadvantage would be that index.js would just contain everything and would not have any knowledge of what is actually needed.

At this point I had to introduce index.js to have a second entry point. I wonder if there is a possibility to use the app entry point, run rolllup, then filter everything from a second entry point or AST tree.

I must admit I do not have enough knowledge, but is there something like AST manipulation? Would an AST manipulation library work with rollup?

(EDIT: rephrased almost everything)

thisconnect commented Dec 31, 2015

Do you think that this approach is ok? One disadvantage would be that index.js would just contain everything and would not have any knowledge of what is actually needed.

At this point I had to introduce index.js to have a second entry point. I wonder if there is a possibility to use the app entry point, run rolllup, then filter everything from a second entry point or AST tree.

I must admit I do not have enough knowledge, but is there something like AST manipulation? Would an AST manipulation library work with rollup?

(EDIT: rephrased almost everything)

@thisconnect

This comment has been minimized.

Show comment
Hide comment
@thisconnect

thisconnect Jan 1, 2016

I am going to try a separate common node module, which should keep things simpler. Since I want it as simple as possible anyway :)

thisconnect commented Jan 1, 2016

I am going to try a separate common node module, which should keep things simpler. Since I want it as simple as possible anyway :)

@Victorystick

This comment has been minimized.

Show comment
Hide comment
@Victorystick

Victorystick Jan 1, 2016

Member

That might be a good idea, until we figure out how best to do this. 👍

Member

Victorystick commented Jan 1, 2016

That might be a good idea, until we figure out how best to do this. 👍

@therealklanni

This comment has been minimized.

Show comment
Hide comment
@therealklanni

therealklanni Jan 16, 2016

Possibly related, I was just trying to figure out if Rollup supports multiple outputs. I figured to do this I would have to configure multiple separate builds (😦) and use excludes to enforce not bundling my internal lib into the main bundle file (to be required/imported). But in my experimenting it seems that the exclude option doesn't prevent my internal lib from being rolled into the main bundle file.

therealklanni commented Jan 16, 2016

Possibly related, I was just trying to figure out if Rollup supports multiple outputs. I figured to do this I would have to configure multiple separate builds (😦) and use excludes to enforce not bundling my internal lib into the main bundle file (to be required/imported). But in my experimenting it seems that the exclude option doesn't prevent my internal lib from being rolled into the main bundle file.

@thisconnect

This comment has been minimized.

Show comment
Hide comment
@thisconnect

thisconnect Jan 17, 2016

hi, I'd like to share my current setup for manually splitting code into a shared library and app.

https://gist.github.com/thisconnect/c5b3cb626953dd3b0001

At this point I am still not 100% about the correct order of the npm, commonjs and babel plugins :)
but nevertheless this seems to work, using an lib entry point.

thisconnect commented Jan 17, 2016

hi, I'd like to share my current setup for manually splitting code into a shared library and app.

https://gist.github.com/thisconnect/c5b3cb626953dd3b0001

At this point I am still not 100% about the correct order of the npm, commonjs and babel plugins :)
but nevertheless this seems to work, using an lib entry point.

@therealklanni

This comment has been minimized.

Show comment
Hide comment
@therealklanni

therealklanni Jan 17, 2016

Thanks @thisconnect, I think this will be helpful for me 👍

therealklanni commented Jan 17, 2016

Thanks @thisconnect, I think this will be helpful for me 👍

@thisconnect

This comment has been minimized.

Show comment
Hide comment
@thisconnect

thisconnect Jan 21, 2016

This issue by @Rich-Harris was more about automatic code splitting and got a bit hijacked to manual code splitting. Maybe rename this issue to manual code splitting and open a new one for auto code splitting?

thisconnect commented Jan 21, 2016

This issue by @Rich-Harris was more about automatic code splitting and got a bit hijacked to manual code splitting. Maybe rename this issue to manual code splitting and open a new one for auto code splitting?

@shannonmoeller

This comment has been minimized.

Show comment
Hide comment
@shannonmoeller

shannonmoeller Apr 13, 2016

This is the only feature keeping me from adopting rollup. Manual splitting isn't an option as it forces all of my modules (and dev team members) to be aware of the code splitting.

Has work been started? I'd love to contribute. Super looking forward to this feature so I can drop browserify and factor-bundle.

shannonmoeller commented Apr 13, 2016

This is the only feature keeping me from adopting rollup. Manual splitting isn't an option as it forces all of my modules (and dev team members) to be aware of the code splitting.

Has work been started? I'd love to contribute. Super looking forward to this feature so I can drop browserify and factor-bundle.

@AndrewIngram

This comment has been minimized.

Show comment
Hide comment
@AndrewIngram

AndrewIngram Aug 15, 2016

I'm wondering if there's a way to define rollup "boundaries" (for lack of a better term) as config. So that rollup doesn't do anything to imports at the boundaries, leaving them for something like webpack to handle as a second pass.

AndrewIngram commented Aug 15, 2016

I'm wondering if there's a way to define rollup "boundaries" (for lack of a better term) as config. So that rollup doesn't do anything to imports at the boundaries, leaving them for something like webpack to handle as a second pass.

@tivac

This comment has been minimized.

Show comment
Hide comment
@tivac

tivac Aug 18, 2016

Contributor

I started looking at this a bit, it's not possible to achieve via plugin w/ existing hooks but a naive implementation seems almost doable.

I started futzing with this as a plugin: https://github.com/tivac/rollup-plugin-bundles

The first sticking point I've found is that the ongenerate hook runs after output is generated. It makes sense given the name but means that ongenerate doesn't work for the purpose I was hoping to use it for. Based on looking at Bundle.js it looks like the transformBundle hook would also be too late, hrmph 😒

I'm sure that even if I hack up rollup to add an onbeforegenerate hook (ugh that name) I'll find some issues w/ my first-pass plan, which is just to yank the modules w/ multiple deps out of the Bundle instance.

Contributor

tivac commented Aug 18, 2016

I started looking at this a bit, it's not possible to achieve via plugin w/ existing hooks but a naive implementation seems almost doable.

I started futzing with this as a plugin: https://github.com/tivac/rollup-plugin-bundles

The first sticking point I've found is that the ongenerate hook runs after output is generated. It makes sense given the name but means that ongenerate doesn't work for the purpose I was hoping to use it for. Based on looking at Bundle.js it looks like the transformBundle hook would also be too late, hrmph 😒

I'm sure that even if I hack up rollup to add an onbeforegenerate hook (ugh that name) I'll find some issues w/ my first-pass plan, which is just to yank the modules w/ multiple deps out of the Bundle instance.

@tivac

This comment has been minimized.

Show comment
Hide comment
@tivac

tivac Aug 18, 2016

Contributor

Well, I did what I promised and hacked up rollup.js to add an onbeforegenerate hook. If I splice the shared module out of the bundle.orderedModules it seems to generate mostly-correct code. Haven't checked the map yet.

Still a ways to go on how to turn the array of removed Module instances into actual usable code.

tivac/rollup-plugin-bundles@7544cd8

Contributor

tivac commented Aug 18, 2016

Well, I did what I promised and hacked up rollup.js to add an onbeforegenerate hook. If I splice the shared module out of the bundle.orderedModules it seems to generate mostly-correct code. Haven't checked the map yet.

Still a ways to go on how to turn the array of removed Module instances into actual usable code.

tivac/rollup-plugin-bundles@7544cd8

@tivac

This comment has been minimized.

Show comment
Hide comment
@tivac

tivac Aug 18, 2016

Contributor

Ugh, spoke too soon. Late now but tomorrow I'll detail all the ways this plan won't work 😦

Contributor

tivac commented Aug 18, 2016

Ugh, spoke too soon. Late now but tomorrow I'll detail all the ways this plan won't work 😦

@tivac

This comment has been minimized.

Show comment
Hide comment
@tivac

tivac Aug 18, 2016

Contributor

Issues

  1. I'm currently using rollup-plugin-multi-entry to get multiple files into rollup, but that only supports multiple inputs -> one output.
  2. The hooks aren't available to plugins to modify the Bundle instance before the bundle is generated (#372 (comment))

So it seems like for this to be possible rollup would need to natively support multiple inputs that map to multiple outputs, otherwise there's going to need to be some serious Bundle editing going on to extract shared modules or modules that are part of a specific input and then generating new Bundle instances for them to take advantage of code generation.

Or maybe I just don't know rollup well enough yet and I'm missing something obvious. I'll take another look at this in a bit.

Contributor

tivac commented Aug 18, 2016

Issues

  1. I'm currently using rollup-plugin-multi-entry to get multiple files into rollup, but that only supports multiple inputs -> one output.
  2. The hooks aren't available to plugins to modify the Bundle instance before the bundle is generated (#372 (comment))

So it seems like for this to be possible rollup would need to natively support multiple inputs that map to multiple outputs, otherwise there's going to need to be some serious Bundle editing going on to extract shared modules or modules that are part of a specific input and then generating new Bundle instances for them to take advantage of code generation.

Or maybe I just don't know rollup well enough yet and I'm missing something obvious. I'll take another look at this in a bit.

@tivac

This comment has been minimized.

Show comment
Hide comment
@tivac

tivac Aug 19, 2016

Contributor

Decided to tackle Issue 1 first, because after looking at rollup.js it seems simple. I'll know for sure once I write some tests, but here's my first crack at it.

tivac@f489050?w=1

Contributor

tivac commented Aug 19, 2016

Decided to tackle Issue 1 first, because after looking at rollup.js it seems simple. I'll know for sure once I write some tests, but here's my first crack at it.

tivac@f489050?w=1

@snuggs

This comment has been minimized.

Show comment
Hide comment
@snuggs

snuggs Aug 20, 2016

The rollem project currently supports this feature @tivac. Possibly leaves us only with thought 2?

https://github.com/bahmutov/rollem

A tad slow but we'll fix that and delegate the watcher to rollup (if possible). At least does multi-entry/output very well.

Then we get into the manual/automatic discussion (again). However have to start somewhere. Or we'll be talking about this for another 9 months.

I feel like there IS a real need as it's intersecting on various issues being brought up. (i.e. #863)

VERY interested in this and look forward to helping.

snuggs commented Aug 20, 2016

The rollem project currently supports this feature @tivac. Possibly leaves us only with thought 2?

https://github.com/bahmutov/rollem

A tad slow but we'll fix that and delegate the watcher to rollup (if possible). At least does multi-entry/output very well.

Then we get into the manual/automatic discussion (again). However have to start somewhere. Or we'll be talking about this for another 9 months.

I feel like there IS a real need as it's intersecting on various issues being brought up. (i.e. #863)

VERY interested in this and look forward to helping.

@tivac

This comment has been minimized.

Show comment
Hide comment
@tivac

tivac Aug 20, 2016

Contributor

@snuggs rollem could work, I'd rather it was integrated into rollup proper though so code splitting didn't depend on a brittle dance of getting multiple plugins installed in just the right order.

Contributor

tivac commented Aug 20, 2016

@snuggs rollem could work, I'd rather it was integrated into rollup proper though so code splitting didn't depend on a brittle dance of getting multiple plugins installed in just the right order.

@shannonmoeller

This comment has been minimized.

Show comment
Hide comment
@shannonmoeller

shannonmoeller Aug 20, 2016

I agree that this would be best at the rollup level. It seems like there are a couple ideas happening here:

  1. N to 1
  2. N to N
  3. N to N+1

My understanding was that the OP is about 3, but the rollem functionality is 2. Am I correct that this issue is about 3?

shannonmoeller commented Aug 20, 2016

I agree that this would be best at the rollup level. It seems like there are a couple ideas happening here:

  1. N to 1
  2. N to N
  3. N to N+1

My understanding was that the OP is about 3, but the rollem functionality is 2. Am I correct that this issue is about 3?

@snuggs

This comment has been minimized.

Show comment
Hide comment
@snuggs

snuggs Aug 20, 2016

@shannonmoeller correct!

  1. is satisfied by rollup-plugin-multi-entry https://github.com/rollup/rollup-plugin-multi-entry
  2. is satisfied by rollem https://github.com/bahmutov/rollem

I'm kinda with @TrySound on this one. I feel we are already at the tipping point of SRP (Single Responsibility Principle) for rollup. If anything it's in a space where internal features can be exposed via the public API. (i.e. FileWatcher https://github.com/rollup/rollup-watch/blob/master/src/index.js#L10-L39)

That "needing an additional API" pain is a great pain to have for a project that's growing. Should always push back until YAPA (Yet Another Public Api) is a last resort. This will encourage the plugin ecosystem.

snuggs commented Aug 20, 2016

@shannonmoeller correct!

  1. is satisfied by rollup-plugin-multi-entry https://github.com/rollup/rollup-plugin-multi-entry
  2. is satisfied by rollem https://github.com/bahmutov/rollem

I'm kinda with @TrySound on this one. I feel we are already at the tipping point of SRP (Single Responsibility Principle) for rollup. If anything it's in a space where internal features can be exposed via the public API. (i.e. FileWatcher https://github.com/rollup/rollup-watch/blob/master/src/index.js#L10-L39)

That "needing an additional API" pain is a great pain to have for a project that's growing. Should always push back until YAPA (Yet Another Public Api) is a last resort. This will encourage the plugin ecosystem.

@bfred-it

This comment has been minimized.

Show comment
Hide comment
@bfred-it

bfred-it Aug 21, 2016

Member

Config-based splitting is a pain though. I'd rather have a "core" bundle that imports the basics and then requires/loads other functionality when needed.

I like webpack's approach with require.ensure, which not only automatically creates new bundles, but also doesn't burden you with naming and loading each one (i.e. it embeds require.js-like functionality for async loading)

Essentially to create multiple bundles you just need this:

import _ from 'lodash';
var its = my(main, 'bundle');

require.ensure([], require => {
  require('module-with-sub-deps');
  $('.this').is('bundle.1.js');
});

Custom syntax like this would also be great:

async import: {
  import 'jquery';
  $('.this').is('bundle.1.js');
}
Member

bfred-it commented Aug 21, 2016

Config-based splitting is a pain though. I'd rather have a "core" bundle that imports the basics and then requires/loads other functionality when needed.

I like webpack's approach with require.ensure, which not only automatically creates new bundles, but also doesn't burden you with naming and loading each one (i.e. it embeds require.js-like functionality for async loading)

Essentially to create multiple bundles you just need this:

import _ from 'lodash';
var its = my(main, 'bundle');

require.ensure([], require => {
  require('module-with-sub-deps');
  $('.this').is('bundle.1.js');
});

Custom syntax like this would also be great:

async import: {
  import 'jquery';
  $('.this').is('bundle.1.js');
}
@snuggs

This comment has been minimized.

Show comment
Hide comment
@snuggs

snuggs Aug 21, 2016

Correct me if i'm wrong @bfred-it but wouldn't custom syntax be outside the scope of rollup?

snuggs commented Aug 21, 2016

Correct me if i'm wrong @bfred-it but wouldn't custom syntax be outside the scope of rollup?

@tivac

This comment has been minimized.

Show comment
Hide comment
@tivac

tivac Aug 21, 2016

Contributor

I don't want rollup to provide async module loading, certainly. Plenty of solutions for that already.

Contributor

tivac commented Aug 21, 2016

I don't want rollup to provide async module loading, certainly. Plenty of solutions for that already.

@pspeter3

This comment has been minimized.

Show comment
Hide comment
@pspeter3

pspeter3 Apr 10, 2017

I think there is value in allowing multiple entry points that split out common chunks.

pspeter3 commented Apr 10, 2017

I think there is value in allowing multiple entry points that split out common chunks.

@cowwoc

This comment has been minimized.

Show comment
Hide comment
@cowwoc

cowwoc Apr 17, 2017

Sorry for throwing a wrench into this discussion, but here is an interesting benchmark I just ran across: https://medium.com/outreach-engineering/tree-shaking-vs-code-splitting-a-real-world-benchmark-bbbf36245db3

Code-splitting will increase the complexity of the tool/configuration, so there has to be a pretty compelling benefit to warrant it. If I understand correctly, the results of this benchmark seem to imply that the performance difference between code splitting (async multiple) and not bundling at all (async individual) is so minimal that you might want to reconsider implementing this feature altogether.

cowwoc commented Apr 17, 2017

Sorry for throwing a wrench into this discussion, but here is an interesting benchmark I just ran across: https://medium.com/outreach-engineering/tree-shaking-vs-code-splitting-a-real-world-benchmark-bbbf36245db3

Code-splitting will increase the complexity of the tool/configuration, so there has to be a pretty compelling benefit to warrant it. If I understand correctly, the results of this benchmark seem to imply that the performance difference between code splitting (async multiple) and not bundling at all (async individual) is so minimal that you might want to reconsider implementing this feature altogether.

@andyearnshaw

This comment has been minimized.

Show comment
Hide comment
@andyearnshaw

andyearnshaw Apr 17, 2017

andyearnshaw commented Apr 17, 2017

@shannonmoeller

This comment has been minimized.

Show comment
Hide comment
@shannonmoeller

shannonmoeller Apr 17, 2017

@cowwoc The desire here is for both optimizations, not one vs another. My use cases involve minimizing the data over the wire for low-end devices and service plans.

shannonmoeller commented Apr 17, 2017

@cowwoc The desire here is for both optimizations, not one vs another. My use cases involve minimizing the data over the wire for low-end devices and service plans.

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Apr 18, 2017

@shannonmoeller is right: dynamic loading and rollup-style optimizations are not mutually exclusive. One ideal world would be to have multiple bundles, each with internal rollup-style optimizations, that export only the dependencies needed by other bundles.

ghempton commented Apr 18, 2017

@shannonmoeller is right: dynamic loading and rollup-style optimizations are not mutually exclusive. One ideal world would be to have multiple bundles, each with internal rollup-style optimizations, that export only the dependencies needed by other bundles.

@cowwoc

This comment has been minimized.

Show comment
Hide comment
@cowwoc

cowwoc Apr 18, 2017

@andyearnshaw I'm actually not against code splitting. Ironically, I ran across this issue while researching how to add code-splitting to my rollup configuration.

The thing that caught my attention about the benchmarking article is their point that with HTTP2 around the corner download latency will be decreasing. This trend is true for mobile as well, even if it might not be the case today.

The "not bundling at all" approach increases complexity of the application, as it requires a loader,

Not necessarily. Eventually browsers will support ES6 modules, in which case loaders won't be necessary (but parsing time will remain a problem). In the meantime, I was planning to manually specify all JS dependencies in the HTML <head>.

I agree with the rest of you, though, that dynamic loading (you mean async loading right?) and rollup-style optimizations are not mutually-exclusive. This is precisely why I filed this issue: #1369

cowwoc commented Apr 18, 2017

@andyearnshaw I'm actually not against code splitting. Ironically, I ran across this issue while researching how to add code-splitting to my rollup configuration.

The thing that caught my attention about the benchmarking article is their point that with HTTP2 around the corner download latency will be decreasing. This trend is true for mobile as well, even if it might not be the case today.

The "not bundling at all" approach increases complexity of the application, as it requires a loader,

Not necessarily. Eventually browsers will support ES6 modules, in which case loaders won't be necessary (but parsing time will remain a problem). In the meantime, I was planning to manually specify all JS dependencies in the HTML <head>.

I agree with the rest of you, though, that dynamic loading (you mean async loading right?) and rollup-style optimizations are not mutually-exclusive. This is precisely why I filed this issue: #1369

@lastmjs

This comment has been minimized.

Show comment
Hide comment
@lastmjs

lastmjs Apr 18, 2017

I would like to emphasize that not bundling at all most definitely decreases the complexity of an application, if all browser standards are fully in play and optimized. We're in the middle of launching a production application and we've decided to do no bundling whatsoever. Our setup is very minimal and allows us to emulate the behavior the browser has always had. Just load the scripts you need through script tags. That model is very easy to grok for component-based architectures.

I guess what I'm trying to say is that we should be looking towards no bundling as our end goal because it reduces the development complexity of our applications. I'll be working on this much more over the summer, but this project is how we're doing it if anyone is interested: https://github.com/lastmjs/zwitterion

That's actually the slightly outdated project, but I will be combining it with the project that we actually use for production soon: https://github.com/lastmjs/zwitterion-production

I think these projects are promising. The idea is to transpile all requested files on the server and then serve them to the user. There are a number of optimizations available to explore.

I wonder if we could somehow use Rollup server-side to transpile and tree-shake requested files, with no build-process necessary.

@cowwoc I wonder if any of this could apply to #1369

lastmjs commented Apr 18, 2017

I would like to emphasize that not bundling at all most definitely decreases the complexity of an application, if all browser standards are fully in play and optimized. We're in the middle of launching a production application and we've decided to do no bundling whatsoever. Our setup is very minimal and allows us to emulate the behavior the browser has always had. Just load the scripts you need through script tags. That model is very easy to grok for component-based architectures.

I guess what I'm trying to say is that we should be looking towards no bundling as our end goal because it reduces the development complexity of our applications. I'll be working on this much more over the summer, but this project is how we're doing it if anyone is interested: https://github.com/lastmjs/zwitterion

That's actually the slightly outdated project, but I will be combining it with the project that we actually use for production soon: https://github.com/lastmjs/zwitterion-production

I think these projects are promising. The idea is to transpile all requested files on the server and then serve them to the user. There are a number of optimizations available to explore.

I wonder if we could somehow use Rollup server-side to transpile and tree-shake requested files, with no build-process necessary.

@cowwoc I wonder if any of this could apply to #1369

@bfred-it

This comment has been minimized.

Show comment
Hide comment
@bfred-it

bfred-it Apr 18, 2017

Member

@lastmjs HTTP compression doesn't work across files; by unbundling your scripts you're increasing your payload's size. I think this is off topic too.

Member

bfred-it commented Apr 18, 2017

@lastmjs HTTP compression doesn't work across files; by unbundling your scripts you're increasing your payload's size. I think this is off topic too.

@andyearnshaw

This comment has been minimized.

Show comment
Hide comment
@andyearnshaw

andyearnshaw Apr 18, 2017

@cowwoc

The "not bundling at all" approach increases complexity of the application, as it requires a loader

Not necessarily. Eventually browsers will support ES6 modules, in which case loaders won't be necessary (but parsing time will remain a problem).

Browsers supporting modules in any useful manner is still a ways off. Simple script importing is useful for small applications with very few dependencies but it doesn't scale well as dependencies and code size increase. I've experienced this first-hand using SystemJS to load ES modules in the browser. As you add dependencies that use different module formats or directory structures, you go deeper down the rabbit hole trying to tie everything together nicely. This is the increase in application complexity I was talking about.

In the meantime, I was planning to manually specify all JS dependencies in the HTML <head>.

Good luck with that 😝. Seriously, though, I don't think this is a good approach at all. Code-splitting allows you to specify dependencies at the point they are used in the code. By specifying scripts in the <head>, you have to ensure that dependencies are available before referencing them. Again, this works ok for small, 1-page apps but becomes a nightmare as you scale up. +Complexity.

As for HTTP/2, it doesn't address the requirement to defer loading of components until they're required. Eventually, yes, HTTP/2 and import() will give us a workable solution. But as long as people need to support older operating system/browser combinations that don't implement both of these features, bundling and code splitting will be required.

andyearnshaw commented Apr 18, 2017

@cowwoc

The "not bundling at all" approach increases complexity of the application, as it requires a loader

Not necessarily. Eventually browsers will support ES6 modules, in which case loaders won't be necessary (but parsing time will remain a problem).

Browsers supporting modules in any useful manner is still a ways off. Simple script importing is useful for small applications with very few dependencies but it doesn't scale well as dependencies and code size increase. I've experienced this first-hand using SystemJS to load ES modules in the browser. As you add dependencies that use different module formats or directory structures, you go deeper down the rabbit hole trying to tie everything together nicely. This is the increase in application complexity I was talking about.

In the meantime, I was planning to manually specify all JS dependencies in the HTML <head>.

Good luck with that 😝. Seriously, though, I don't think this is a good approach at all. Code-splitting allows you to specify dependencies at the point they are used in the code. By specifying scripts in the <head>, you have to ensure that dependencies are available before referencing them. Again, this works ok for small, 1-page apps but becomes a nightmare as you scale up. +Complexity.

As for HTTP/2, it doesn't address the requirement to defer loading of components until they're required. Eventually, yes, HTTP/2 and import() will give us a workable solution. But as long as people need to support older operating system/browser combinations that don't implement both of these features, bundling and code splitting will be required.

@shannonmoeller

This comment has been minimized.

Show comment
Hide comment
@shannonmoeller

shannonmoeller Apr 18, 2017

For those of us who would like the code-splitting feature, I think we all agree on two things:

  1. It's not the future yet.
  2. Current solutions are less than desirable.

The original issue envisions this usage of the final (preferably automated) solution:

<!-- a.html -->
<script src="shared.js"></script>
<script src="a.js"></script>

<!-- b.html -->
<script src="shared.js"></script>
<script src="b.js"></script>

I believe module loading, alternate patterns, and worthiness of code-splitting are off topic. I'd like to see more discussion around what the internals of shared.js, a.js, and b.js look like. I think the simplest solution is to use UMD and some sort of object reference or destructuring.

Thus, given input similar to this:
https://gist.github.com/shannonmoeller/f7f80a4da3e034518cb5524d3ec0e056

I might expect output similar to this:
https://gist.github.com/shannonmoeller/280dda1f47e222c1ee88e5613bd01897

shannonmoeller commented Apr 18, 2017

For those of us who would like the code-splitting feature, I think we all agree on two things:

  1. It's not the future yet.
  2. Current solutions are less than desirable.

The original issue envisions this usage of the final (preferably automated) solution:

<!-- a.html -->
<script src="shared.js"></script>
<script src="a.js"></script>

<!-- b.html -->
<script src="shared.js"></script>
<script src="b.js"></script>

I believe module loading, alternate patterns, and worthiness of code-splitting are off topic. I'd like to see more discussion around what the internals of shared.js, a.js, and b.js look like. I think the simplest solution is to use UMD and some sort of object reference or destructuring.

Thus, given input similar to this:
https://gist.github.com/shannonmoeller/f7f80a4da3e034518cb5524d3ec0e056

I might expect output similar to this:
https://gist.github.com/shannonmoeller/280dda1f47e222c1ee88e5613bd01897

@jessehattabaugh

This comment has been minimized.

Show comment
Hide comment
@jessehattabaugh

jessehattabaugh Jul 3, 2017

My two cents: code-splitting is more useful for lazy-loading chunks, than generating common chunks like the OP wants. This would require a runtime to determine which chunks have been loaded. Am I correct in assuming that this is something Roll-up's maintainers are loathe to do? If that's the case, could a plugin, or complimentary tool perform this job, and what would that look like?

jessehattabaugh commented Jul 3, 2017

My two cents: code-splitting is more useful for lazy-loading chunks, than generating common chunks like the OP wants. This would require a runtime to determine which chunks have been loaded. Am I correct in assuming that this is something Roll-up's maintainers are loathe to do? If that's the case, could a plugin, or complimentary tool perform this job, and what would that look like?

@MikeMatusz

This comment has been minimized.

Show comment
Hide comment
@MikeMatusz

MikeMatusz Oct 10, 2017

Lazy loading is my use case as well. There are already ways of manually generating common chunks with rollup. I'm currently using webpack to bundle a large Angular application with lazy-loaded routes. What I'm using rollup for currently is bundling several Angular libraries shared by multiple teams. I was hoping to try bundling our application with it as well, but that won't be practical without a feature like this.

MikeMatusz commented Oct 10, 2017

Lazy loading is my use case as well. There are already ways of manually generating common chunks with rollup. I'm currently using webpack to bundle a large Angular application with lazy-loaded routes. What I'm using rollup for currently is bundling several Angular libraries shared by multiple teams. I was hoping to try bundling our application with it as well, but that won't be practical without a feature like this.

@ctavan

This comment has been minimized.

Show comment
Hide comment
@ctavan

ctavan Nov 23, 2017

Chrome 63 and Safari Technology Preview 24 will both support dynamic import().

Me too, I'd love to be able to chunk my rollup bundles and use dynamic import() for lazy loading of these chunks.

ctavan commented Nov 23, 2017

Chrome 63 and Safari Technology Preview 24 will both support dynamic import().

Me too, I'd love to be able to chunk my rollup bundles and use dynamic import() for lazy loading of these chunks.

@lukastaegert lukastaegert removed this from the future milestone Nov 29, 2017

@guybedford

This comment has been minimized.

Show comment
Hide comment
@guybedford

guybedford Jan 24, 2018

Contributor

Closing as the feature is now live, will also be iterating on enhancements as we get feedback, but these can track in new issues.

Contributor

guybedford commented Jan 24, 2018

Closing as the feature is now live, will also be iterating on enhancements as we get feedback, but these can track in new issues.

@guybedford guybedford closed this Jan 24, 2018

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