Skip to content

Advanced module path mappings #180

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

Closed
exk0730 opened this issue Jul 27, 2016 · 12 comments
Closed

Advanced module path mappings #180

exk0730 opened this issue Jul 27, 2016 · 12 comments

Comments

@exk0730
Copy link

exk0730 commented Jul 27, 2016

Current behavior

To import a module:
import { BaseComponent } from '../../frameworks/core/index';
(as seen here)

Expected/desired behavior

To import the same module:
import { BaseComponent } from 'frameworks';

Other information
I've tried a bunch of different things, but either
a) the Typescript compiler doesn't like the import statement (all intellisense becomes broken)
or b) the SystemJS build can't find the module.

If I solve a, then b occurs and vice versa - I can't get both of them to work properly. I was wondering if anyone was doing something like this in their own project, or if someone could point me in the right direction to solve this issue.

Also, I was wondering what this line did in the seed.config.ts file and if it's at all useful for my issue.

Thanks!

@yvoronen
Copy link

yvoronen commented Jul 28, 2016

If you switch to bleeding edge TypeScript (1.9+), I haven't tested this in 2.0beta, then you can do this via tsconfig.json.

Add the following to tsconfig.json:

  "compilerOptions": {
  ...
     "baseUrl": "./",
     "paths": {
            "*": [
                "src/client/app/*",
            ]
      }
  }

More info here: TypeStrong/atom-typescript#833

@yvoronen
Copy link

yvoronen commented Jul 28, 2016

It looks like it is available in TypeScript 2.0 beta as well. Here is stackoverflow reference:
http://stackoverflow.com/questions/34925992/how-to-avoid-imports-with-very-long-relative-paths-in-angular-2/34926643

@exk0730
Copy link
Author

exk0730 commented Jul 28, 2016

Hey @yvoronen! Yeah, I actually upgraded to 2.0 just for this purpose - it fixes a but then b breaks. Here are the relevant parts of the configuration files:

{
    "compilerOptions": {
        "target": "es5",
        "module": "commonjs",
        "declaration": false,
        "removeComments": true,
        "noLib": false,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "sourceMap": true,
        "baseUrl": "./src",
        "paths": {
            "frameworks": ["client/app/frameworks"],
            "components": ["client/app/main/components"],
            "pages": ["client/app/main/pages"],
            "utility": ["client/app/main/utility"]
        }
    },
    "compileOnSave": false
}
...
map: {
      frameworks: 'src/client/app/frameworks/index',
      components: 'src/client/app/main/components/index',
      pages: 'src/client/app/main/pages/index'
    }
...

Keep in mind I moved the components directory from the base seed into a "main" directory.

So with the above two edits to the configurations, I can do:

import { BaseComponent } from 'frameworks/index'; and the Typescript compiler is satisfied, but the SystemJS build.dev breaks (can't find module frameworks/index).

If I do: import { BaseComponent } from 'frameworks'; the SystemJS build.dev runs, but the Typescript compiler / my IDE screws up.

@yvoronen
Copy link

yvoronen commented Jul 29, 2016

it seems you omitted the '*'s. Just below should be sufficient to allow you to import from frameworks/index. You can also get to your components via import ... from 'main/components/index'.

"paths": {
            "baseUrl": "./",
            "*": [
                "src/client/app/*",
            ]
      }

My IDE (VSCode) currently does not like these imports, but gulp build.dev works just fine and there are no compile errors. I have another project with same setup, and IDE is totally cool with that.

I think you have to set proper path to your local typescript SDK in the IDE, or maybe there is another issue. I haven't had time to compare to the other project where IDE works ok.

@yvoronen
Copy link

yvoronen commented Jul 29, 2016

I got IDE to work now. The problem was that there was a second tsconfig.json inside src/client, which the IDE was picking up. That one should look as follows, because it is relative to src/client

"paths": {
            "baseUrl": "./",
            "*": [
                "app/*",
                "app/main/*"
            ]
      }

And you might need to edit .vscode/settings.json (opens via Preferences->Workspace settings) to add the below

  "typescript.tsdk": "<absolute-path-to-project>/node_modules/typescript/lib"

@NathanWalker
Copy link
Owner

@exk0730 love the idea of this and always wanted to do it.
@yvoronen Very exciting to hear you got this working; I'll look fwd to trying this soon; I'd be interested in a PR along these lines if you ever get time to submit one.

@exk0730
Copy link
Author

exk0730 commented Aug 1, 2016

@yvoronen Thanks! I'm going to look into this today.

@exk0730
Copy link
Author

exk0730 commented Aug 1, 2016

@NathanWalker @yvoronen I was able to get MOST of the functionality working (tests are screwed up and the desktop app does not load the data.json file) - I mostly just wanted to see the app run in each environment. A few things to get it up and running:

  1. In project.config.ts, add the following:
 this.SYSTEM_CONFIG['packages'] = Object.assign({}, this.SYSTEM_CONFIG['packages'], {
  'frameworks': {
    defaultExtension: 'js',
    main: 'index.js'
  }
});

this.SYSTEM_CONFIG['paths'] = Object.assign({}, this.SYSTEM_CONFIG['paths'], {
  'frameworks': `app/frameworks`,
});

this.SYSTEM_BUILDER_CONFIG['packages'] = this.SYSTEM_CONFIG['packages'];
  1. In the frameworks folder, add an index.ts file and add the following:
export * from './core/index';
export * from './analytics/index';
export * from './app/index';
export * from './electron/index';
export * from './i18n/index';
  1. Change the root package.json to use "typescript": "^2.0.0", (and run npm install - make sure the typescript directory in node_modules is 2.0 instead of 1.8.10).

  2. Add the following to the root tsconfig.json (thanks to @yvoronen)

"baseUrl": "./",
"paths": {
  "*": ["src/client/app/*"]
}

Note: baseUrl should be OUTSIDE the paths object.

  1. Add the following to src/client/package.json:
"baseUrl": "./",
"paths": {
  "frameworks": ["app/frameworks"]
}
  1. You should now be able to change main.web.ts to import DIRECTLY from frameworks like so:
    import { WindowService, ConsoleService, CORE_PROVIDERS, ANALYTICS_PROVIDERS, MultilingualService, APP_PROVIDERS, AppConfigService } from 'frameworks';
    Your IDE should not complain and the build should run. You can import directly from frameworks anywhere OUTSIDE the frameworks directory.

Some notes...

  • I've only been able to export/import barrels for directories directly underneath src/client/app. For example, the frameworks/index.ts file exports analytics, core, electron, etc directly from their index.ts files like so: export * from './core/index'; which could be simplified to export * from './core'; but I haven't been able to figure that out.
  • Technically, I should be able to do export * from './test/index'; in the frameworks barrel, but so far it blows up the app and I haven't been able to figure out why, so I left it out in the frameworks index file.

@rbosneag
Copy link

rbosneag commented Oct 5, 2016

I have the same need as the OP while sketching the structure of a new ng2 app and play around with folders - which means I need to update paths to all model classes and other modules all over the place every time I make a change.

@exk0730 your solution above may work but I won't try it as it seems to be overkill and I disagree with the idea of importing a file that imports others modules (unless it's quite necessary for the project).

I wonder if maybe SystemJS actually offers this alias thing that I need but I just cannot get it to work (I keep trying solutions from here and there but either IntelliSense is broken or the module cannot be found, same as the OP).

For example, after completing the Tour Of Heroes tutorial (took me 4h), I realized that the systemjs.config.json below is actually used to reference modules from alias paths while keeping IntelliSense working (with no paths specified in tsconfig.json).


(function(global) {
    System.config({
        paths: {
            // paths serve as alias
            'npm:': 'node_modules/'
        },
        // map tells the System loader where to look for things
        map: {
            // our app is within the app folder
            app: 'app',
            // angular bundles
            '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
            '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
            '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
            '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
            '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
            '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
            '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
            '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
            // other libraries
            'rxjs': 'npm:rxjs',
            'angular-in-memory-web-api': 'npm:angular-in-memory-web-api'
        },
        // packages tells the System loader how to load when no filename and/or no extension
        packages: {
            app: {
                main: './main.js',
                defaultExtension: 'js'
            },
            rxjs: {
                defaultExtension: 'js'
            },
            'angular-in-memory-web-api': {
                main: './index.js',
                defaultExtension: 'js'
            }
        }
    });
})(this);

With the above file, everything seems to be working fine: IntelliSense available for various imports from RxJS, models under the app folder, everything.

Maybe I'm out of track with the OP but I'd really like to get this working.

@exk0730
Copy link
Author

exk0730 commented Oct 5, 2016

@rbosneag I have since moved away from this seed and have started using Webpack. There were numerous problems with building a production build of NativeScript after I enhanced the seed with path mapping, I couldn't figure out how to fix them. I also had some problems with running tests.

I would suggest not adding module path mapping if you continue with this seed until someone with more knowledge can actually take a crack at it.

As for your "importing a file that imports other modules", I'm not entirely sure what you mean.

@rbosneag
Copy link

rbosneag commented Oct 5, 2016

@exk0730 so all your problems are gone with WebPack? I thought SystemJS is a viable option since ng2 docs rely on it, that's why I kept struggling (and lack of experience with WebPack, of course)

As for the file importing other files I thought it was a trick to load the modules from one central place in the package just to see them loading (using it as a wrapper, let's say) not as you'd actually use that "importer" for project's needs. I came to this idea looking at your SO post but now I guess I was wrong...:)

@exk0730
Copy link
Author

exk0730 commented Oct 5, 2016

@rbosneag I realized I didn't need NativeScript or Electron, so a Webpack starter was a more viable option for me; plus I find Webpack easier to configure, but that's just my personal opinion.

I used this starter and it's been working out perfectly so far (I was even able to add path mappings!) You can look at this file and this webpack configuration to see an example of how I set up path mapping.

If you need more help, hit me up on gitter so we don't clutter this issue :)

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

No branches or pull requests

4 participants