-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
External module resolution logic #2338
Comments
Need to cross reference with comments here too #247 |
One question: What does it mean when X is e.g. '/foo/bar' and you calculate Y + X? Do you resolve X against Y, e.g. like a browser would resolve a URL, so that '/foo/bar' would result in an absolute path? Regarding the path mapping, this approach would not quite solve our problem. What I want to express is that a source file should first be searched in location A, then in location B, then C, and so on. That should be true for all source files, not just for a specific subset (as you do with the pattern matching). The source code of the including file should not care where the included file is located. I presume the harder problem is establishing what the path that is searched in those locations is exactly. If a file is loaded relative to a base URL, we could first resolve all paths relative to that file's relative URL to the base, and then use the result to look up in the search paths. Given a file Y, a require('X'):
The initially passed 'Y' from the command line would also be resolved against the include/search paths. For example, for a file
If you specified
This would allow us to "overlay" the working directory of the user over an arbitrary number of include paths. I think this is essentially the same as e.g. C++ |
... oh and obviously, I mean this as a suggestion to be incorporated into your more complete design that also handles node modules etc. |
Yes, module name that starts with '/' is an absolute path to the file I think path mappings can solve the problem if we allow one entry of it to be mapped to the set of locations {
"*": [ "first/path/*", "/second/path/*" ]
} Having this update module resolution process will look like: var moduleName;
if (moduleName.startsWith(../) || moduleName.startsWith('../')) {
// module name is relative to the file that calls require
return makeAbsolutePath(currentFilePath, moduleName);
}
else {
for(var path of [ moduleName, moduleName + '.ts', moduleName + '.d.ts']) {
var mappedPaths = applyPathMapping(path);
for(var mappedPath in mappedPaths) {
var candidate = isPathRooted(mappedPath) ? mappedPath : makeAbsolute(baseFolder, mappedPath);
if (fileExists(candidate)) {
return candidate;
}
}
}
}
throw PathNotFound; Note: Out of curiosity, do you have many cases when code like |
Re the code example, I think even relative paths should be resolved against the mapped paths. Imagine you have a part of your code base in a different physical location (repository), but still use the conceptually relative path. In general, I think it might be a good idea to have a logical level of paths that get resolved, and then those are matched against physical locations, but the two concepts are orthogonal otherwise - that is, you can have relative or absolute logical paths mapping to any physical location. Our particular use case is that we currently exclusively use absolute rooted include paths ( I see that your example of path mappings is strictly more powerful, but at least from where I stand, I think include directories cover all we need, and might be simpler for tooling to understand & implement. YMMV. |
Would be great if I am open to different suggestions if you want. |
For path mapping AMD/ES6 could you follow the syntax already used by AMD paths common configuration? It maps module ID prefixes, from most-specific to least specific, so e.g.:
In so doing, this leaves open the possibility of the compiler being able to simply consume the same AMD configurations used by an app at runtime, instead of introducing an incompatible equivalent syntax. |
I will give my vote for having This will keep things simpler (no yet another config), and it will clearly indicate that package can be used with TS. |
When package produces single entity (ES6' export default), I assume, declaration file, hopefully generated by compiler, will be something like
|
@3nsoft, i am not sure i understand the question/comment |
@mhegazy I have in mind package that is a single object or function. How will this be done?
In given setting the |
Typescript has a non-ES6 export syntax
and you would import it as:
|
@vladima For the Node case, would it make sense to automatically detect the typing to use based not only on a LOAD_AS_DIRECTORY(X)
This way, I won't have to specify e.g.: {
// ...
"main": "./dist/foo.js",
"typings": "./dist/foo.d.ts"
} but a simple BTW FWIW, I think I also prefer |
@poelstra I'd recall Python's wisdom of "explicit is better". If others are using .d.ts, and format becomes non-Typescript-specific, then it is a good reason to have a separate Here are other fields, which might be useful in the future:
These and other goodies will benefit from having an agreed-upon place in package.json, i.e. |
I think it would be useful to consider adding an extra lookup to the Node case, to get smooth support for non-Typescript packages too (i.e. all the good stuff on DefinitelyTyped). Didn't want to highjack this thread, so created #2839 for it. Curious what you guys think about it, though. |
I didn't notice the |
Having looked through @poelstra's example I definitely agree about calling it |
What is the current status for a package that exports multiple modules? |
Module resolution should work on the underlaying JavaScript level, and not on transpiled language. Stop doing wrong work. Babel never trying to traverse dependencies, that's the purpose of a dependencies bundler which will work on compiled JavaScript level. WebPack and TypeScript guys really do very bad design choices about separation of concerns and isolation of responsibilites. |
Babel doesn't do type checking. To check imports you need to know their location 🌹 |
@avesus Module resolution is a platform/runtime concern, not a language concern. ES6 specifies a syntax for describing and importing modules, but it does not specify a uniform module loader or module resolution strategy that is implemented by all environments where JS runs. While NodeJS and browsers do not yet natively implement a module loader, TypeScript will need to emit different stuff to support different module loaders. |
Dear Asad, NodeJS natively implements module loader. And I mean not LOADING process, And that standard is f**_ly simple: EXPORT YOUR JAVASCRIPT to get it easily This f**ng ClosureScript and TypeScrypt allow to export more than one Mr. Asad, you have to know that Node Modules system along with NPM was best When you write import 'module.ts'; and it's compiled into LOADING of a Babel compiles any JSX and other files without trying to directly load Exporting multiple modules from a single typescript file enforces to create When WebPack (f_**ng too) allows you to import css, coffee, JSX and a lot Hope @sindresorhus and @tj agree with me. It will be very interesting to Mighty Lamers can break all best things made by professionals. Angular2 You're lamers and you're trying to break NPM world of JavaScript magic. On Tuesday, July 5, 2016, Asad Saeeduddin notifications@github.com wrote:
Best Regards, |
@avesus I understand where you are coming from, however we don't have to get so passionate and personal over something like this. We're all just trying to make the best solutions for developers. |
@avesus this is a forum for technical discussions and issue reporting for a programming language and a compiler, and not a political or social forum. The way you express your opinions and the language you have used in this thread are not inducive to a constructive discussion. If you want to contribute to this project, and have an interest in future of the TS/JS tooling, please refrain from using such language, and avoid directing insults to the community members and/or the core team. |
I apologise for super emotional tone of course. Hope future of npm will be Only one simple prayer: please be responsive and smart. Think more before I support the language itself and have nothing against angular or webpack Sorry for the emotional tone. On Wednesday, July 6, 2016, Mohamed Hegazy notifications@github.com wrote:
Best Regards, |
"Babel doesn't do type checking. To check imports you need to know their On Wednesday, July 6, 2016, Ivan Borisenko avesus8@gmail.com wrote:
Best Regards, |
What I advice is to compare modules idea with object files / linker system in C world. TypeScript - compiler. Webpack - linker. If disable TypeScript modules resolution, each *.ts file will be compiled to a *.js file and that *.js file will import dependencies. It allows superfast *.ts files compilation. The command line I use:
It is necessary to have ambient declarations, for example,
Declare reference in *.ts files:
So, It allows to author files written in multiple different languages within one package and export correct All I ask from community is to support this approach widely because it is base of npm modularity and success. |
Problem
Current module resolution logic is roughly based on Node module loading logic however not all aspects of Node specific module loading were implemented. Also this approach does not really play well with scenarios like RequireJS\ES6 style module loading where resolution of relative files names is performed deterministically using the base url without needing the folder walk. Also current process does not allow user to specify extra locations for module resolution.
Proposal
Instead of using one hybrid way to resolve modules, have two implementations, one for out-of-browser workflows (i.e Node) and one for in-browser versions (ES6). These implementations should closely mimic its runtime counterparts to avoid runtime failures when design time module resolution succeeded and vice versa.
Node Resolution Algorithm
Resolution logic should use the following algorithm (originally taken from Modules all toghether):
require(X) from module at path Y
RequireJS/ES6 module loader
require
.Base folder can be either specified explicitly via command line option or can be inferred:
Path mappings can be used to customize module resolution process. In 'package.json' these mappings can be represented as JSON object with a following structure:
Property name represents a pattern that might contain zero or one asterisk (which acts as a capture group). Property value represents a substitution that might contain zero or one asterisk - here it marks the location where captured content will be spliced. For example mapping above for a path 'assert.ts' will produce a string 'project/ts/assert.ts'. Effectively this logic is the same with the implementation of
locate
function in System.js.With path mappings in mind module resolution can be described as:
With path mappings it becomes trivial to resolve some module names to files located on network share or some location on the disk outside the project folder.
Using this mapping relative path 'shared/core' will be mapped to absolute path 'q:/shared/core.ts'.
We can apply the same resolution rules for both modules and tripleslash references though for the latter onces its is not strictly necessary since they do not implact runtime in any way.
The text was updated successfully, but these errors were encountered: