aurelia / loader-webpack

An implementation of Aurelia's loader interface to enable webpack.
MIT License
26 stars 10 forks source link

ViewLocator type error when using Webpack #12

Closed niieani closed 8 years ago

niieani commented 8 years ago

@heruan commented on Mon Jul 11 2016

The CompositionContext interface has viewModel defined as:

/**
* The view model url or instance for the component.
*/
viewModel?: any;

but if it's set to a view model instance when using Webpack, I get this error:

Uncaught (in promise) TypeError: Cannot read property 'endsWith' of undefined(…)
    convertOriginToViewUrl @ aurelia-templating.js:705
    ConventionalViewStrategy @ aurelia-templating.js:563
    createFallbackViewStrategy @ aurelia-templating.js:700
    getViewStrategy @ aurelia-templating.js:691
    (anonymous function) @ aurelia-templating.js:4367

because viewModel seems assumed to be a string.

To reproduce simply use this as main.js in skeleton-esnext-webpack:

import {bootstrap} from 'aurelia-bootstrapper-webpack';
import {App} from "./app";

bootstrap((aurelia) => {
  aurelia.use.standardConfiguration().developmentLogging();
  aurelia.start().then(() => aurelia.setRoot( aurelia.container.get(App), document.body) );
});

This happens using Webpack only, the same logic in skeleton-esnext works as expected.


@EisenbergEffect commented on Mon Jul 11 2016

I believe this is a limitation in Webpack due to the fact that it doesn't function as a true module loader.

@niieani Can you look into this please? This issue has come up repeatedly. Either there's a bug in the Webpack loader or this just isn't possible with Webpack. If it isn't possible, we need to include documentation.

@heruan As a workaround, you can always provide the module id. Another possibility would be to manually associate the module id with the view model like so

import {Origin} from 'aurelia-metadata';

export class MyClass {
}

Origin.set(MyClass, new Origin('./my-class', 'MyClass'));

If you need, you could create a decorator to do this as well, potentially leveraging the module id constants that Webpack makes available. I believe it's module.id but I'm not sure. @niieani can confirm. So, you could do something like this:

function origin(id, name) {
  return function(target) {
   Origin.set(target.constructor, new Origin(id, name || 'Default'));
  }
}

@origin(module.id)
export class MyClass {

}

@heruan commented on Mon Jul 11 2016

Thank you @EisenbergEffect, I hit this also when mapping a route in the router with moduleId set to an external module such as "module-name": using Webpack it fails with Error: Cannot find module './module-name', whereas using JSPM it loads the first export in "module-name" as expected.

Thus, since I'm trying to set view models from external modules as app root and routes, I don't think the Origin workaround could work.


@EisenbergEffect commented on Mon Jul 11 2016

For the routing scenario, I'm not sure how that would work with Webpack. @niieani will have to chime in on that.


@niieani commented on Mon Jul 11 2016

There are no limitations related to Webpack. When using either external resources/modules or paths to modules that cannot be statically analyzed you need to include them in build resources (see the readme of webpack skeleton and webpack-plugin for more info on how to do that). The cited error however looks like a bug. I will investigate. Essentially, everything that works with JSPM or RequireJS should work exactly the same with Webpack assuming proper configuration.


@EisenbergEffect commented on Mon Jul 11 2016

@niieani Thanks! That's good to hear. I know you've got plenty you are working on but if you could add this to your list to investigate, that would be great. I've seen this and similar issues come up a few times.


@heruan commented on Mon Jul 11 2016

Thank you @niieani!

For reference, these are a couple of use cases which fails using Webpack but works with JSPM.

  1. Using an actual module id instead of relative path in RouteConfig.moduleId:
routerConfiguration.mapRoute( { route: '/list', moduleId: 'my-module/list' } );
  1. Using a VM instance in CompositionContext, instead of a string:
// in main configure/bootstrap function
let root = aurelia.container.get(MyApp);
aurelia.setRoot(root, document.body);

@niieani commented on Mon Jul 11 2016

Using an actual module id instead of relative path

@heruan This should work, providing you declare the given moduleId as a build resource in your package.json.

The second issue seems to be with Origin metadata not being set properly for the modules by the webpack loader. This is the one I need to investigate.


@heruan commented on Mon Jul 11 2016

Thank you @niieani I can confirm that declaring modules in package.json/aurelia/build/resources works! I look forward on your investigation for the other case, consider me available for testing.

niieani commented 8 years ago

Fixed in https://github.com/aurelia/webpack-plugin/commit/a69b8f0dad41996d47324c75bb71df1c8dc86cfc.

EisenbergEffect commented 8 years ago

Impressive.

niieani commented 8 years ago

@EisenbergEffect :) While working on this I've also added a deprecation warning here https://github.com/aurelia/webpack-plugin/commit/053592793c312373b059ef866e8beb4578457b7f and made loaders used by the Views configurable here: https://github.com/aurelia/webpack-plugin/commit/b8f87d6973e6d981ef105a4be2a1d076ed829f44

heruan commented 8 years ago

Great! Can't wait to have this released 🌹