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

importing is cumbersome for deeply nested components, how do I set up a map to the app root? #865

Closed
NullVoxPopuli opened this issue May 20, 2016 · 26 comments
Labels
P5 The team acknowledges the request but does not plan to address it, it remains open for discussion

Comments

@NullVoxPopuli
Copy link

$ ng --version
Could not start watchman; falling back to NodeWatcher for file system events.
Visit http://ember-cli.com/user-guide/#watchman for more info.
angular-cli: 1.0.0-beta.2-mobile.3
node: 5.10.1
os: linux x64

how do I set up a mapping for my app root to import?
I'm trying to avoid doing:

import { stuff } from '../../../../../../../components/some/path-to/what/iwant

and would like to do:

import { stuff } from 'myAppName/components/some/path-to/what/iwant

it is more intuitive, to specify an app-relative path, especially when refactoring (so you don't need to open the file tree, and count how many ../ you have...

I've tried adding mappings in my system-config.ts, but I haven't found anything to work.

const map: any = {
  '@app': 'src'
};

doesn't work -- as in:

import { stuff } from '@app/components/mystuff' 

errors on build.

@cdarken
Copy link

cdarken commented May 23, 2016

I see that in system-config.ts we have '@angular': 'vendor/@angular'. This seems to be relative to the dist/ directory. Maybe you can try using directly app/components/stuff.
Just a wild guess, as I'm new at this, still trying to figure things out.

@NullVoxPopuli
Copy link
Author

I had also tried adding '@app': 'app', and it can't find any files using that. :-\

Also, I deleted the dist folder, so it appears that however this needs to be configured, it is pre-build (because the error occurs before the dist folder is even created)

@serhiisol
Copy link
Contributor

serhiisol commented May 23, 2016

you should use map + packages in system-config.js

/** Map relative paths to URLs. */
const map:any = {
  '@web-app': './app/'
};

/** User packages configuration. */
const packages:any = {
  '@web-app': {
    format: 'cjs',
    defaultExtension: 'js',
    main: 'index'
  }
};

Also tsconfig.json in compilerOptions section

"paths": {
      "@web-app": ["./app/index.ts"],
      "@web-app/*": [
        "./app/*"
      ]
    }

and then you can use something like that:

import {environment} from '@web-app';

Note: it works without -prod option, with -prod it toggles error:

$ ng build -prod
Could not start watchman; falling back to NodeWatcher for file system events.
Visit http://ember-cli.com/user-guide/#watchman for more info.
⠹ Building"{{content-for}}" has been deprecated and will be removed before RC.
Build failed.
The Broccoli Plugin: [BundlePlugin] failed with:
Error tracing app/+login/login.component.js at file:///Users/serhiysolonko/Development/Projects/web-app/tmp/bundle_plugin-input_base_path-kOVkldZW.tmp/0/app/+login/login.component.js
    Loading app/+login/index.js
    Loading app/web-app.component.js
    Loading app/index.js
    Loading main.js
    Error: Unable to calculate canonical name to bundle file:///Users/serhiysolonko/Development/Projects/web-app/app//index.js. Ensure that this module sits within the baseURL or a wildcard path config.
    at getCanonicalNamePlain (/Users/serhiysolonko/Development/Projects/web-app/node_modules/systemjs-builder/lib/utils.js:220:13)
    at getCanonicalName (/Users/serhiysolonko/Development/Projects/web-app/node_modules/systemjs-builder/lib/utils.js:145:19)
    at /Users/serhiysolonko/Development/Projects/web-app/node_modules/systemjs-builder/lib/trace.js:471:36

The broccoli plugin was instantiated at:
    at BundlePlugin.Plugin (/Users/serhiysolonko/Development/Projects/web-app/node_modules/broccoli-plugin/index.js:10:31)
    at BundlePlugin.CachingWriter [as constructor] (/Users/serhiysolonko/Development/Projects/web-app/node_modules/broccoli-caching-writer/index.js:21:10)
    at BundlePlugin (/Users/serhiysolonko/Development/Projects/web-app/node_modules/angular-cli/lib/broccoli/angular-broccoli-bundle.js:10:36)
    at Angular2App._getBundleTree (/Users/serhiysolonko/Development/Projects/web-app/node_modules/angular-cli/lib/broccoli/angular2-app.js:421:22)
    at Angular2App._buildTree (/Users/serhiysolonko/Development/Projects/web-app/node_modules/angular-cli/lib/broccoli/angular2-app.js:159:21)
    at new Angular2App (/Users/serhiysolonko/Development/Projects/web-app/node_modules/angular-cli/lib/broccoli/angular2-app.js:53:23)
    at module.exports (/Users/serhiysolonko/Development/Projects/web-app/angular-cli-build.js:6:10)
    at Class.module.exports.Task.extend.setupBroccoliBuilder (/Users/serhiysolonko/Development/Projects/web-app/node_modules/angular-cli/lib/models/builder.js:55:19)
    at Class.module.exports.Task.extend.init (/Users/serhiysolonko/Development/Projects/web-app/node_modules/angular-cli/lib/models/builder.js:89:10)
    at new Class (/Users/serhiysolonko/Development/Projects/web-app/node_modules/core-object/core-object.js:18:12)
    at Class.module.exports.Task.extend.run (/Users/serhiysolonko/Development/Projects/web-app/node_modules/angular-cli/lib/tasks/build.js:15:19)
    at /Users/serhiysolonko/Development/Projects/web-app/node_modules/angular-cli/lib/commands/build.js:32:24
    at lib$rsvp$$internal$$tryCatch (/Users/serhiysolonko/Development/Projects/web-app/node_modules/rsvp/dist/rsvp.js:1036:16)
    at lib$rsvp$$internal$$invokeCallback (/Users/serhiysolonko/Development/Projects/web-app/node_modules/rsvp/dist/rsvp.js:1048:17)
    at /Users/serhiysolonko/Development/Projects/web-app/node_modules/rsvp/dist/rsvp.js:331:11
    at lib$rsvp$asap$$flush (/Users/serhiysolonko/Development/Projects/web-app/node_modules/rsvp/dist/rsvp.js:1198:9)

@NullVoxPopuli
Copy link
Author

@SergeySolonko can you explain a bit what each option does, and how it affects the various parts of the build process?

I tried copy-pasting what you had, and I still get the error "Cannot find module '@web-app/anything'"

@serhiisol
Copy link
Contributor

serhiisol commented May 23, 2016

@NullVoxPopuli
so tsconfig.json option responsible for compilation, system-config.js responsible for js loading.

this config works for standard folder configuration, at least first part. It should be something like this:

screenshot at may 23 15-02-25

with system-config you're creating kind-a symlink to get access to specific module, with tsconfig.json you're saying which file you're expecting to get and that it should be compiled

now @web-app basically it's a link to src/app/index.ts module

@web-app/* it's a link to rest of the files, e.g. @web-app/shared/index

I hope I've explained it clearly :)

@hansl
Copy link
Contributor

hansl commented May 23, 2016

  '@web-app/*': {
    format: 'cjs',
    defaultExtension: 'js'
  }

does nothing. The * is not understood in SystemJS packages.

@hansl
Copy link
Contributor

hansl commented May 23, 2016

The path mapping is only used by TypeScript compiler to know which import corresponds to which modules. SystemJs operates on another level.

@serhiisol
Copy link
Contributor

yes correct that was redundant, but still when you're trying to compile with _prod mode - it fails

@tydanielson
Copy link

I was able to get the system-config.js file to work correctly, but I added paths to the compilerOptions section of tsconfig.json and am unable to import, the compiler throws this error: Cannot find module '@app' . I also looked at the schema for tsconfig.json and can't find anything about paths ...
https://www.typescriptlang.org/docs/handbook/compiler-options.html

Am I missing something? Here is my tsconfig.json...

{
  "compileOnSave": false,
  "compilerOptions": {
      "paths": {
        "@app" : ["//test.externalhost.com/app/index.ts"],
        "@app/*": [
            "//test.externalhost.com/app/*"
        ]
      },
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "mapRoot": "@app",
    "module": "commonjs",
    "moduleResolution": "node",
    "noEmitOnError": true,
    "noImplicitAny": false,
    "outDir": "../dist/",
    "rootDir": ".",
    "sourceMap": true,
    "target": "es5",
    "inlineSources": true
  },

  "files": [
    "main.ts",
    "typings.d.ts"
  ]
}

@colltoaction
Copy link

I'm just starting with ng2, and it seemed very intuitive to me to try to use a full path. Why do people tend to use relative paths instead?

@NullVoxPopuli
Copy link
Author

@tinchou, how do you use a full path? how do you ref your app root?

@aciccarello
Copy link
Contributor

@tinchou Using relative paths can be easier when referencing a file in the same folder or a folder above. If you move a folder you don't have to fix all of the imports within that folder. But when the files are deeply nested and you are referencing something that is in the root of your source directory, I agree that full path tends to be simpler.

Also, the import system is related to ES2015 modules/TypeScript/System JS more than Angular 2 itself.

@colltoaction
Copy link

@NullVoxPopuli I haven't set it up, I'm just saying it didn't work by default.

@aciccarello true, but maybe having an alias to the root in the default template would help.

@serhiisol
Copy link
Contributor

@tinchou that's what we are trying to get - to have a reference to very top folder (app folder). It works well for non-production build, for production - it fails. #865 (comment)

@colltoaction
Copy link

@SergeySolonko this is my +1 to having an alias to the app root by default with ng new (that works in production too, of course 😛)

@filipesilva filipesilva added type: enhancement P5 The team acknowledges the request but does not plan to address it, it remains open for discussion labels Jun 2, 2016
@Blasz
Copy link

Blasz commented Jun 14, 2016

The following works for me for both ng build and ng build -prod.

$ ng --version
(node:5016) fs: re-evaluating native module sources is not supported. If you are using the graceful-fs module, please update it to a more recent version.
Could not start watchman; falling back to NodeWatcher for file system events.
Visit http://ember-cli.com/user-guide/#watchman for more info.
angular-cli: 1.0.0-beta.5
node: 6.2.1
os: linux x64

tsconfig.json - Add the following paths property to compilerOptions

"compilerOptions": {
  ...
  "paths": {
    "app/*": [
      "./app/*"
    ]
  }
}

Now the app directory should be able to be imported from as follows:

import { Logger } from 'app/shared/index';

Caveats

App specific barrels aren't able to be referenced by directory name when imported from an app-relative path regardless of whether a barrel definition exists in system-config.ts (not sure why).

import { Logger } from 'app/shared';       // won't work
import { Logger } from 'app/shared/index'; // will work

As an aside, I have no idea why the paths entry in tsconfig.json works when it should only be available in typescript@next (with the target milestone of 2.0) - microsoft/TypeScript#5728.
As far as I can see both angular-cli and the default ng project scaffold use typescript 1.8.10

@chapati23
Copy link

chapati23 commented Jul 19, 2016

yeah, we definitely need aliases. webpack makes that pretty straightforward: https://webpack.github.io/docs/configuration.html#resolve-alias

obviously there's still the typescript compilation step in between which makes it a bit more tricky but the newly introduced paths compiler option should be able to solve this.

i have a relatively small app and already have super ugly relative import-paths. all the nice encapsulation through componentisation is basically destroyed because if you have relative paths everywhere, your app is basically a microlith with super high coupling.

@cdarken
Copy link

cdarken commented Jul 19, 2016

Yeah, I've realized just recently that the import must work for the compile step and then for the dist version, where the files are loaded by SystemJs. The search paths for the typescript compiler seem to be kind of hardcoded, you can't tell it to use aliased paths like with SystemJs.

@Blasz
Copy link

Blasz commented Aug 8, 2016

Anyone know how to do this using the webpack version?

@filipesilva
Copy link
Contributor

A more broad issue that includes this one is being tracked in #1465.

Settings paths in tsconfig as shown in #865 (comment) should work. We've also removed barrels (they've become a bit unecessary with NgModules) so the problem @Blasz was experiencing with referencing them shouldn't be an overall thing.

@Blasz
Copy link

Blasz commented Aug 16, 2016

@filipesilva Note that #865 (comment) no longer works for me in the majority of cases with the webpack version. I can no longer import files from using the root-relative path when the file being imported contains other common imports (which it will in 95% of cases). It looks like a false positive circular-dependency related bug.

@filipesilva
Copy link
Contributor

@Blasz is that a CLI or a typescript bug though?

@Blasz
Copy link

Blasz commented Aug 23, 2016

@filipesilva I'm not quite sure but would lean towards CLI rather than typescript since the errors are being thrown by the webpack module resolution code rather than the typescript compiler. I'll try to investigate further and lodge a proper issue once I verify what the issue is exactly.

@filipesilva
Copy link
Contributor

@Blasz appreciated!

@dedeibel
Copy link

@Blasz thanks a lot.

Had to write a little script to convert our existing import paths. Maybe someone can use it too: https://gist.github.com/dedeibel/65ebfc4ccb53a758952e4d812c832831 (perl)

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 7, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
P5 The team acknowledges the request but does not plan to address it, it remains open for discussion
Projects
None yet
Development

No branches or pull requests