admin管理员组

文章数量:1313806

Update[09/12/2017 16:58 EST]

Added reason why I hesitate to use the natively-supported non-relative import with my own modules to the bottom of this question.

Update[09/12/2017 12:58 EST]:

Per request, I made the file structure below reflect my actual use case. Which is a nested view module requesting a utility module somewhere up the directory tree.


Per request

In both TypeScript and ES6, one can import custom module by

// Relative
import { numberUtil } from './number_util';
// OR
// Non-relative
import { numberUtil } from 'number_util';

And according to TypeScript docs (link), one should:

... use relative imports for your own modules that are guaranteed to maintain their relative location at runtime.

... Use non-relative paths when importing any of your external dependencies.

My problem here is that I have a project structure like this:

project/
  |--utils
  |    |--number_util.ts
  |--views
  |    |--article_page
  |         |-- editor_view
  |                |--editor_text_area.ts

And when I include utils/number_util inside my editor_text_area module, the import statement looks like:

import { numberUtil } from './../../../utils/number_util';

Which is long and not readable and, worst of all, difficult to maintain: whenever I need to move editor_text_area, I will have to update each these relative paths, when in the meantime I can just use the non-relative way of

import { numberUtil } from 'utils/number_util';

Does anyone have any suggestions on how best to do module imports to achieve the highest readability and maintainability?


But using the non-relative way poses a problem (other than that it is not remended by official docs): what if I installed an npm module that has the same name with the module I'm importing? On that note, it is not as safe as the uglier alternative mentioned above.

Update[09/12/2017 16:58 EST]

Added reason why I hesitate to use the natively-supported non-relative import with my own modules to the bottom of this question.

Update[09/12/2017 12:58 EST]:

Per request, I made the file structure below reflect my actual use case. Which is a nested view module requesting a utility module somewhere up the directory tree.


Per request

In both TypeScript and ES6, one can import custom module by

// Relative
import { numberUtil } from './number_util';
// OR
// Non-relative
import { numberUtil } from 'number_util';

And according to TypeScript docs (link), one should:

... use relative imports for your own modules that are guaranteed to maintain their relative location at runtime.

... Use non-relative paths when importing any of your external dependencies.

My problem here is that I have a project structure like this:

project/
  |--utils
  |    |--number_util.ts
  |--views
  |    |--article_page
  |         |-- editor_view
  |                |--editor_text_area.ts

And when I include utils/number_util inside my editor_text_area module, the import statement looks like:

import { numberUtil } from './../../../utils/number_util';

Which is long and not readable and, worst of all, difficult to maintain: whenever I need to move editor_text_area, I will have to update each these relative paths, when in the meantime I can just use the non-relative way of

import { numberUtil } from 'utils/number_util';

Does anyone have any suggestions on how best to do module imports to achieve the highest readability and maintainability?


But using the non-relative way poses a problem (other than that it is not remended by official docs): what if I installed an npm module that has the same name with the module I'm importing? On that note, it is not as safe as the uglier alternative mentioned above.

Share Improve this question edited Sep 12, 2017 at 21:01 benjaminz asked Sep 11, 2017 at 20:54 benjaminzbenjaminz 3,2383 gold badges38 silver badges51 bronze badges 4
  • 3 Usually a nested hierarchy that deep is a sign of an architecture issue. What's making it so deep? – loganfsmyth Commented Sep 11, 2017 at 20:58
  • @loganfsmyth please see my updated code snippet, I included a real-world use case very similar to mine – benjaminz Commented Sep 12, 2017 at 16:04
  • Having had that top-level "views" folder in an application before, I personally found it frustrating for exactly this reason. I opted to just move editor_view and other such to the top instead. It's already got view in the name. Sticking them all in a folder called view and in a page-specific folder doesn't offer any meaningful logic. If you need page-specific logic like "what is loaded on article_view", the import/export dependency graph will already tell you that. – loganfsmyth Commented Sep 12, 2017 at 16:10
  • I must say, I would not pletely flatten your source hierarchy. I actually find it quite useful to have this kind of structuring in non-trivial projects. Just don't let it get too deep. So if editor_view could actually be useful to other views too, but incidentally is just needed by article_page, you should pull it up a level. – raphinesse Commented Sep 12, 2017 at 20:04
Add a ment  | 

2 Answers 2

Reset to default 5

Depending on your project tooling and structure, you have some options.

A) You could publish part of your dependencies as stand-alone modules, perhaps in a private registry. You can then install them with npm and require them like any other external dependency.

B) Many module systems support some sort of path mapping. The vue-js webpack template uses webpack's alias feature to set @ to the source code root. TypeScript supports path mapping too. After you introduce that mapping you can use

import { numberUtil } from '@/utils/number_util';

This approach basically introduces a private namespace for your modules. It is safe, in that you could only ever shadow an npm module with the name @ which is an invalid name and therefore cannot exist.

For your example, you would have to have these entries in your pilerOptions:

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

Or if you only want to import modules from utils, you could change the mapping to "@/*": ["utils/*"] and import using '@/number_util'.

C) Another thing to consider is to improve your project structure. Depending on your actual project, it might make sense to apply the facade pattern at one point or another. Maybe inject the dependency into editor_text_area instead of letting it import it itself.

you can add "baseUrl": "./src", to you tsconfig.json,

then you can import * as utils from 'utils' to import ./src/utils/index.ts

本文标签: javascriptRelative vs nonrelative module import for custom modulesStack Overflow