aurelia / webpack-plugin

A plugin for webpack that enables bundling Aurelia applications.
MIT License
90 stars 36 forks source link

Unexpected behavior with monorepo #145

Open Sayan751 opened 6 years ago

Sayan751 commented 6 years ago

I'm submitting a bug report

Please tell us about your environment:

Current behavior: The plugin is not working as expected when packages are symlinked. To demonstrate the behavior, I have created a repository. I have a monorepo (using lerna) with following structure:

|-modules
|  |-main       // aurelia-webpack project
|  |-myplugin  // aurelia plugin as npm module
|  |-services    // an npm module containing services
|-package.json  // contains npm scripts using lerna to build app

If I want to register some module specific routes from myplugin, I need to use

{ moduleId: PLATFORM.moduleName("./views/plugin-home"), route: "myplugin" }

With this, the webpack build for main works iff I set resolve.symlinks: false in my webpack config. However, this causes another problem which portrays as if the DI is failing. To clarify, let's assume that there is a MyService exported from services package, which is used in both main/main.ts and myplugin/index.ts with Container.instance.get. Now, one would expect that same instance will be provided in both the places. However, that is not the case as MyService is being resolved from 2 different sources:

Expected/desired behavior:

Sayan751 commented 6 years ago

A workaround for this can be to define alias in webpack config for the shared modules (services in the above example). With that, the duplication of nested modules can be avoided, even with symlink set to false.

...
resolve: {    
    alias: {
      'services': path.resolve(__dirname, "../services"), ...
    } ...
}, ...

However, this can also be cumbersome when there are several shared modules.

jods4 commented 6 years ago

I've had problems with monorepo recently as well. It can get hairy rather quickly and there are many variations. For example you did not consider what happens if you hoist your node_modules at root.

I am not sure what the best solution here is. Any idea is welcome.

Maybe I should add a mono-repo mode to the plugin?

If I try to sum up the options so far:

Sayan751 commented 6 years ago

@jods4 I indeed hoisted the dependencies to root node_modules folder, but still the local node_modules (the ones, which are in my modules folder), stays in individual node_modules folder even if I have hoisted. And I have not found (or maybe I have missed) any lerna documentation to avoid that using npm.

However, when one uses yarn (workspace) + lerna, all dependencies for all projects in a monorepo can be hoisted in the root node_modules folder. And with that the alias can be removed. You may check it here in my repository's yarn-ws branch.

And regarding the dedupe webpack plugin, I think it is long deprecated in favor of npm dedupe (which does not work in my case) and yarn workspace (I think).

Alexander-Taran commented 6 years ago

as far as I remember there are options in yarn workspaces to keep some of the modules.. not hoisted.. would that help?

Sayan751 commented 6 years ago

@Alexander-Taran With yarn workspace, it works properly. In that setup as well, one need to use symlink: false, but no alias is required.

indfnzo commented 6 years ago

I might be having a similar issue.

My structure is something like this:

|- clients
|  |- common                // an aurelia plugin containing common reusable components
|  |  |- comps_dir
|  |  |- index.js
|  |- app1                  // aurelia webpack app
|  |  |- src
|  |  |  |- ...             // local resources for this app
|  |  |  |- main.ts         // calls /clients/common as a plugin/feature
|  |  |- webpack.config.js
|  |  |- package.json
|  |- app2
|  |  |- ...
|  |- app3
|  |  |- ...

from within the webpack config of each app, I'm adding the common directory as a module and alias:

resolve: {
    extensions: ['.js'],
    modules: [path.resolve(__dirname, '../common'), 'src', 'node_modules'],
    alias: {
        common: path.resolve(__dirname, '../common')
    }
},

Despite the common modules being resolved and loaded by the individual apps, the modules doesn't seem like they're getting transpiled by babel since I'm getting syntax errors:

ERROR in ../common/elements/xxx.js
Module build failed: SyntaxError: C:/Users/xxxx/Documents/Projects/xxx/clients/common/elements/xxx.js: Unexpected token (4:0)

  2 | import { ApiService } from 'services/api';
  3 |
> 4 | @inject(ApiService)
    | ^
  5 | export class UiXxx {
  6 |   constructor(api) {
  7 |           this.api = api;

My commons dir doesn't compile itself. It's literally just all the source files since I expect the apps using them to compile these along with everything else. These common modules can't go on their own builds, since Sass files inside common are tightly coupled with the architecture of each app. Am I doing something wrong here?

Btw, all the solutions at https://github.com/babel/babel-loader/issues/293 doesn't seem like they work for my case.

Sayan751 commented 6 years ago

@jemhuntr I think this is a different issue.

You have not specified if you are using lerna or not. If not you may benefit from using something like lerna or yarn workspace.

I would suggest to build your common module as an npm package. If there are some app specific stuffs inside your common module, then it is not really common. If you want to style your apps and put all css in a common stylesheet, then a better alternative would be to use css modules. Here are some resources for css module:

Then you can build your common module and use lerna to add it to your apps. That way the common module will reside in node_modules of each app. And you don't have define the alias for common module unless there is a nested dependency, such as app-->common and app-->someotherModule-->common.

Hope this helps.

indfnzo commented 6 years ago

@Sayan751 Yeah, I'm not using lerna nor do I have a monorepo structure. This is just the most relevant resource I found about the specific issue, and I figured out eventually that the issue is most likely with webpack upstream.

And thanks, CSS Modules is definitely the way to go. The last time I tried getting it to work didn't exactly go well though, but I might try it again on my next project.

I really just have been looking for an easy way to share local resources between multiple webpack builds, as the apps are literally just copy-pastes of each other with different implementations and content structure.