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

Support dynamic imports for Vue components #6

Closed
rangermeier opened this issue Oct 12, 2018 · 8 comments
Closed

Support dynamic imports for Vue components #6

rangermeier opened this issue Oct 12, 2018 · 8 comments

Comments

@rangermeier
Copy link
Contributor

Following up to the discussion in #4 I open a new issue for this.

v1.0.1-alpha.2 works fine for examples/es6-dynamic-import but for examples/vue-cssextract (the HelloWorld.vue component is loaded async) the output still looks like this:

out/examples/vue-cssextract/0.js  <--- imported by both main.js and main.modern.js, sometimes using the modern target, somtimes the legacy target
out/examples/vue-cssextract/main.css
out/examples/vue-cssextract/main.js
out/examples/vue-cssextract/main.modern.js
out/examples/vue-cssextract/vendors~main.js
out/examples/vue-cssextract/vendors~main.modern.js

When I import a plain js file dynamically from within a Vue component, webpack will however emit both a modern and a legacy chunk for it. E.g. adding another dependency.js and altering the component config of examples/vue-cssextract/App.vue like this:

export default {
  name: 'app',
  components: {
    HelloWorld: () => import('./components/HelloWorld.vue')
  },
  mounted() {
    import('./dependency').then(dep => {
      console.log(dep('hello'))
    })
  }
}

will build the following files:

out/examples/vue-cssextract/0.js  <--- this is HelloWorld.vue, imported by both main.modern.js and main.js
out/examples/vue-cssextract/1.js  <--- this is modern dependency.js, imported by main.modern.js
out/examples/vue-cssextract/2.js  <--- this is legacy dependency.js, imported by main.js
out/examples/vue-cssextract/main.js
out/examples/vue-cssextract/main.modern.js
out/examples/vue-cssextract/vendors~main.js
out/examples/vue-cssextract/vendors~main.modern.js
@DanielSchaffer
Copy link
Owner

DanielSchaffer commented Oct 12, 2018

Believe it or not, this actually makes sense since BabelMultiTargetPlugin.loader isn't being used for the vue files. If the loader isn't used and it's dynamically imported, the plugin won't try to target it. It doesn't work when I just add it in, I'm guessing because it emits more than just JS, so it's going to need some more logic to pick out the JS chunks.

EDIT: I've got a proof-of-concept solution in v1.0.1-alpha.3. It requires adding BabelMultiTargetPlugin.targetingLoader to your vue rule loaders, which doesn't actually do anything except function as a marker so the plugin knows it's supposed to be targeted.

DanielSchaffer added a commit that referenced this issue Oct 12, 2018
DanielSchaffer added a commit that referenced this issue Oct 14, 2018
- BabelMultiTargetPlugin.loader is now a method that accepts an optional webpack Loader
- remove placeholder loader concept
- consolidate/simplify babel-loader replacement logic

supports #6
@DanielSchaffer
Copy link
Owner

I've revamped the BabelMultiTargetPlugin.loader usage a bit - you'll now replace your 'vue-loader' with BabelMultiTargetPlugin.loader('vue-loader') in your .vue rule, in addition to using BabelMultiTargetPlugin.loader() in your .js rule. Since it's a breaking change, it's in v2.0.0-alpha.1. Let me know if this gets you up and running, and I'll cut the non-prerelease.

@rangermeier
Copy link
Contributor Author

That's amazing! Thanks for your work to bring this plugin forward!

v2.0.0-alpha.1 works for me for a simple vue-loader setup.

However I'm getting errors when dynamically importing plain JS code from Vue components. I prepared another small example: https://github.com/rangermeier/webpack-babel-multi-target-plugin/tree/feature/example-vue-dynamic-import (please let me know if I should submit a PR for this, or should merge it with the vue-cssextract example)

When a file is dynamically imported at two or more points in an application, there's an error Module not found: Error: Unexpected lazy module request, likely due to mixing ES Harmony and CommonJs imports of @angular/core, the build however passes but the dependency is built in only one of modern/legacy targets.

DanielSchaffer added a commit that referenced this issue Oct 15, 2018
DanielSchaffer added a commit that referenced this issue Oct 15, 2018
- BabelMultiTargetPlugin.loader is now a method that accepts an optional webpack Loader
- remove placeholder loader concept
- consolidate/simplify babel-loader replacement logic

supports #6
@DanielSchaffer
Copy link
Owner

DanielSchaffer commented Oct 15, 2018

This one's a little trickier. I'm getting a two pairs of requests for the dependency file, I'm guessing because at that point, Webpack doesn't realize it's the same module (since I change the request when targeting). In other use cases, this generally indicates an error, as you can tell from the error being thrown. Looks like I might need to allow the same file to get blind targeted more than once.

Also, thank YOU for working with me on this and helping me get Vue properly supported. I appreciate being able to check against someone with a real world use case rather than just trying to come up with a contrived example myself.

DanielSchaffer added a commit that referenced this issue Oct 16, 2018
@DanielSchaffer
Copy link
Owner

DanielSchaffer commented Oct 16, 2018

Okay, some progress! v2.0.0-alpha.2 should work without using that webpackChunkName annotation - it ends up using numbered file names, which I understand is less desirable, but it does seem to work.

However, when using the webpackChunkName annotation, it looks like it tries to merge the otherwise separate targeted chunks. I'll need to look further into how that feature works so I can figure out how to get the chunk tagged correctly so you end up with, for example, dep.js and dep.modern.js.


Update - fixed chunk naming in v2.0.0-alpha.3

@rangermeier
Copy link
Contributor Author

v2.0.0-alpha.3 fixes the issue with dynamic imports, also named chunks are working for me now. However I encountered another problem with normal imports of npm modules, see #8 .

Again, thank you for working on this plugin.

@DanielSchaffer
Copy link
Owner

So, a couple things:

This wasn't actually an issue with the plugin - moment requires (ha!) a little finessing when used in an ES6 environment. I added a resolve alias for it, and it's working now - though it's still showing a warning for loading locale data, so you'll need to do something more for that (look around for using ContextReplacementPlugin to load only the locales you need instead of ALL of them).

That said, it might be worth looking into using a different library like Luxon to get the most out of ES6 and things like tree shaking.

Also, the syntax for using the module from dependency.js was wrong - default exports get shoved behind a .default property when imported like that, so I just changed it to use a named export.

@DanielSchaffer
Copy link
Owner

Assuming there aren't any further issues, I'm going to close this and cut 2.0.0.

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

No branches or pull requests

2 participants