Skip to content
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

unable to use "lazy" in html, "Can't resolve 'bundle' #89

Open
jinwangchina opened this issue Jan 31, 2017 · 19 comments
Open

unable to use "lazy" in html, "Can't resolve 'bundle' #89

jinwangchina opened this issue Jan 31, 2017 · 19 comments
Assignees
Labels

Comments

@jinwangchina
Copy link
Contributor

jinwangchina commented Jan 31, 2017

I'm submitting a bug report

  • Library Version:
    1.2.0

Please tell us about your environment:

  • Operating System:
    Windows 7

  • Node Version:
    6.9.4

  • NPM Version:
    3.10.10

  • Webpack AND Version
    webpack 2.2.0

  • Browser:
    all

  • Language:
    TypeScript

Current behavior:
When I specify "lazy" to "require" tag in html.
<require from="./component/component" lazy></require>

And perform webpack bundle, no split bundle created, and can observe the following warning:
WARNING in ./src ^\.\/.*$ Module not found: Error: Can't resolve 'bundle' in 'C:\Users\Jin\IdeaProjects\TestAurelia\src' BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders. You need to specify 'bundle-loader' instead of 'bundle'. @ ./src ^\.\/.*$ @ ./~/aurelia-loader-webpack/dist/commonjs/aurelia-loader-webpack.js

Maybe the following source code at line 50 and 51
if (lazy || bundle) output +=bundle?;

should be fixed to
if (lazy || bundle) output +=bundle-loader?;

Expected/desired behavior:
chunk bundle should be created for my component, like 1.chunk.js, 2.chunk.js and etc ...

  • What is the expected behavior?

  • What is the motivation / use case for changing the behavior?

@niieani
Copy link
Contributor

niieani commented Feb 1, 2017

@jods4 should we switch to chunk="chunkName" in the <require> as a attribute in HTML? Is lazy even supported in by your plugin?

@jods4
Copy link
Contributor

jods4 commented Feb 1, 2017

lazy is not an option currently.

In any case, we should be careful when discussing because it can have different meanings:

  • In the webpack bundle-loader definition, lazy makes no sense because aurelia-loader always loads then executes modules right away.
  • If you mean "in a separate chunk/file but loaded sync" vs "loaded async on demand" it could make sense but there's nothing like that yet and chunk option always uses the latter.

I have not added this to reduce the complexity of v1 and because I'm unsure if this is really the idomatic webpack way to go about it:

  • If you want sync but distinct files there are other ways to go about it, notably chunking plugins.
  • You can also use the current "on demand" chunk and load it sync in your homepage. The penalty for the async proxy is really low.

Does it make sense to support chunk on <require>?
Maybe?
We can discuss scenarios, I have to look how it could integrate with the parser.
As I explained above chunk is currently == on demand code split, which makes a ton of sense for routes, maybe not as much for the local resources used by a view (you'll want them loaded when your view is used, right)?

My current thinking based on our discussions plus the examples @Vheissu gave me is that we should add some facilities to re-organize your code in various files (sync), and keep chunk an async code split point.

@jinwangchina
Copy link
Contributor Author

jinwangchina commented Feb 1, 2017

Thanks for responding to my issue!

I got to know "lazy" usage from the document below:
http://aurelia.io/hub.html#/doc/article/aurelia/framework/latest/bundling-webpack/5

  1. with lazy in <require> tag, it will generate separated chunk for ts and html for a component ("lazy" works after the fix per above), for example, 1.chunk.js for ts file, 2.chunk.js for html file. However, this is actually not what I want to see.
  2. with lazy in package.json for a component, it only generates a chunk file including both ts and html, which is good. But if the component html has <require> tag (without lazy) to a "sub-component", interestingly, the "sub-component" is included in the app.bundle.js rather than the chunk bundle.

In addition, with this plugin, seems that webpack (2.2.0) behaves in different way:

  1. it always bundles everything under ./src, even includes those standalone files which are not imported by any file.
  2. require.ensure()/System.import()/import() doesn't work anymore for code split.
  3. can't change the order of <link rel="stylesheet"> in the generated index.html if I have another entry including css. The css file extracted from ./src will always be placed lastly in the <head> tag of the generated index.html.

I wonder if they are expected behaviors with Aurelia-Webpack?

@niieani
Copy link
Contributor

niieani commented Feb 1, 2017

@jods4

Yes, in the old plugin lazy always meant:

"in a separate chunk/file but loaded sync" vs "loaded async on demand"

Latest experimental versions even accept chunk='...' as an alternative to lazy, exactly because of the unfortunate naming.


Does it make sense to support chunk on ?

I think so. Potentially, you might be requiring quite a bit from the View, e.g. other Custom Elements, ValueConverters, BindingBehaviors.

(you'll want them loaded when your view is used, right)

Yes, but you might want to have a chunk for a set of ValueConverters, which is used by multiple views. chunk='custom-value-converters' could be a solution to that problem.


My current thinking based on our discussions plus the examples @Vheissu gave me is that we should add some facilities to re-organize your code in various files (sync), and keep chunk an async code split point.

Agreed. This is how it worked till now in v1 with lazy. lazy was used to create an async code split point.

@jods4
Copy link
Contributor

jods4 commented Feb 1, 2017

Yes, but you might want to have a chunk for a set of ValueConverters, which is used by multiple views.

If the views are not in the same chunk to start with, that's exactly what CommonsChunkPlugin does.

I don't want to do the effort to think this through for v2.0, but we surely can adjust for a later release if we feel there is a need. It's certainly not a blocker.

@nathanchase
Copy link

nathanchase commented Feb 24, 2017

So, in lieu of doing something like this in the package.json:

...
        {
          "path": "home",
          "bundle": "home",
          "lazy": true
        },
        {
          "path": "login",
          "bundle": "login",
          "lazy": true
        }
...

how would we go about creating separate chunks for separate "pages/paths" of our application with Aurelia+Webpack? Some pages of my code use specific external vendor plugins that do not need to be loaded on the login page, for example.

@jods4
Copy link
Contributor

jods4 commented Feb 24, 2017

@nathanchase
Like so:
https://github.com/jods4/aurelia-webpack-build/blob/master/demos/03-Code_splits/src/app.ts#L10

The second parameter to moduleName is a chunk name that creates an async/lazy code split on the webpack dependency. Perfect place to use it is on routes.

@nathanchase
Copy link

Woah. I've never seen PLATFORM.moduleName anywhere in the docs before. Is that something new? I don't see anything about assigning chunk names via the aurelia router anywhere else online. I assume that's something specific only to the webpack builds?

@jods4
Copy link
Contributor

jods4 commented Feb 24, 2017

@nathanchase that's all new for the upcoming 2.0 webpack plugins.
I assumed that context when you said "in lieu of doing something like this in the package.json:".
If you are using the current 1.x webpack plugins, please disregard what I just said.

@nathanchase
Copy link

Ah. Yeah, I've been waiting to see those release, but I'm not using TypeScript, and it seems like those experimental builds are all TS-based thus far.

@jods4
Copy link
Contributor

jods4 commented Feb 24, 2017

They work just the same in JS.
Remove the stuff you don't need -- the TS loader, the .ts default extension -- and you should be good to go.

@jordan-ware
Copy link

The PLATFORM.moduleName("./module", "chunk") works wonders if your component is navigated to by the router.

I have a custom element which I am hoping to achieve a similar outcome. Both approaches mentioned in the docs for webpack bundler don't seem to work:

centralized, in the package.json

With the centralized approach, my custom element appears to be bundled with the module that has a <require> to it.

as parameters of the <require> tag of your .html View files

The lazy and bundle attributes on <require> aren't currently working.

Will these methods eventually be supported, or are there alternative ways to achieve code splitting a custom element to load async on demand?

@jods4
Copy link
Contributor

jods4 commented Aug 28, 2017

I don't support lazy attribute on <require> by design.

What are you trying to achieve?

If Aurelia encounters a <require> in your view, it has to load it before the view can be used. As such, it's counter-productive to not put the element in the same chunk as the view (or a parent chunk). You only add one more network round-trip, i.e. you make your app slower.

The view itself can easily be lazy-loaded as you noted, along with the local resources it uses.

Lazy loading is for stuff that you might not need, or might need later. By putting them in a different chunk you optimize the starting time of your page. A route is prime example of something you might need later -- maybe not at all.

The local resource of a view is something you need right now when loading the view. It's not a good boundary point to perform lazy loading.

@jordan-ware
Copy link

example bundle
Here's the example scenario. Note the dotted lines are my current bundle/chunk boundaries. My aim is to have the expensive plugin loaded only when the specific child module that depends on it is loaded.

What approach would you choose to get the jquery plugin custom element to get chunked, and only loaded when the child module is routed to?

The lazy on <require> seemed a good way to explicitly inform webpack to code split and make it async. I'm fairly new to webpack code splitting so sorry if I'm not clear in my approach. 😅

Any help on the matter would be appreciated, and I'm hoping the users who have tried lazy on <require> from the Aurelia hub documentation may find this information very useful.

@jods4
Copy link
Contributor

jods4 commented Aug 29, 2017

I think the boundary would be better placed around yellow "child routed module" then.

Until navigated to they are not loaded at all.
When navigated, everything they need is loaded at once including the fat jQuery plugin.

If you want to put plugins used in more than one lazy route in a single chunk, you can use CommonChunksPlugin for that. It's flexible and lets you decide which chunks you want to extract stuff from, what the minimum size should be before creating a common chunk and more.

The hub docs are still for the 1.x plugins, sorry for the confusion. The new plugins are a complete rewrite and don't share much with the old ones.

@jordan-ware
Copy link

I think my understanding was still very vague when it came to when modules are loaded. The CommonChunksPlugin is pretty much what I wanted.

I think the only alternative to delay the loading of this library, without chunking my child modules, is to use dynamic import, with which I have granular control over when the resource is loaded.

Much appreciated @jods4!

@jods4
Copy link
Contributor

jods4 commented Sep 3, 2017

You should check the behavior of your application but I don't think CommonChunksPlugin would not delay load the expensive lib.
It prevents loading it twice by using a shared chunk for all other modules that use the expensive lib.

To actually delay load the expensive part, you need to make the at the pages that require it, which is easy enough.

@jordan-ware
Copy link

Yeah, I went with your suggestion and just set the boundary around my child plugin and then did a specific commons chunk for that expensive custom element. I'm guessing this is similar to how the old <require lazy> used to behave?

...you need to make the at the pages that require it...

Have I confirmed what you meant here?

@jods4
Copy link
Contributor

jods4 commented Sep 6, 2017

If by just set the boundary around my child plugin you meant child route, then yes! :)

You can observe what is loaded and when in the network analyzer of your browser. It should be nice (route and expensive component are only loaded when navigating to the route, and only once).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants