-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
import with absolute path? #203
Comments
There are no absolute paths in a browser, those are called URLs which are supported. Absolute paths don't make sense in deno IMO because they would mean 100% non portable code, which makes no sense why you would generate that? Paths are relative to the module, which means all the module needs to know is its own contained little world. Absolute paths invariably would leak local machine details and not be portable to things like a CI server, or anyone else's machine. |
Indeed, in the browser when you import something starting with Node imports from the OS root. Which makes the code non portable for browsers. |
Or have a |
Exactly, I'm talking about |
Then what are the proposed semantics of defining the base? |
What about a flag?
EDIT: @nicolasparada I just realized you already said this |
Or don't. Just the project root. |
What is the project root? There is no concept of a project with deno at the moment, and highly unlikely to be. I am still not sure what problem this would solve once you accept that even with a base all paths are relative. |
Now that you say it, you're right. I was confused with the browser and serving the content. import { whatever } from '../../../some/os/path/file.js' Right? |
Just to write down an example: Assume the entry file is located at (absolute path on an os level, just for clearification): In that case the base would be Writing If the entry file was located at
Even if there's no "project" from a Deno perspective, there will always be one from another perspective. You will still check-in a project folder into version control e. g.
What problem does it solve? Here are some other sources that describe the problem:
In another article I just read the term "relative path hell" which describes it very well. I understand that Deno won't support aliases as it looks right now, but my proposal is a possible workaround or alternative. EDIT: okay, I've found a way to describe the problem in a short way: With With Hope that makes it more clear. |
It's true that in JavaScript we don't enforce project structure (like Go and its cd /home/username/projects/project-name
deno main.ts Now, imports starting with Deno aims to be secure and browser compatible... For example, in that import { something } from '../other-project/lib.ts' |
cd /home/username/projects/project-name
deno some-module/main.ts If you try to run that, now the "root" will be cd /home/username/projects/project-name
deno --base . some-module/main.ts |
In the first you still have to know where/how the base is defined and hope that is consistent across every environment it runs in and that doesn't change between invocations of deno. |
While this is true, it is only one thing to remember. With relative paths you have to remember <number of files in your project> things. (Where am I currently? How many dirs do I have to go up? What dirs do I have to enter?) Oh, I just noticed another problem with relative paths. Let's take this import statement as an example: import { func } from '../folder/file.ts' Now imagine there are several If you write
You check-in your project into a VCS, check-out on another machine and the base is still the same because your folder structure is the same as well. If your base changes for some reason I think you do something very wrong - like changing the project structure or moving just a subfolder of your project to another system. Why would you do that, if you're not explicitly working with something like submodules? (If that was even a reason. I don't know.)
Why would it change there? In order for a change to happen here you have to change your project structure on purpose. This doesn't happen for no reason. And if you do that it would mess up relative paths as well, or actually even more easily. About the security concerns @nicolasparada mentions: Deno is said to have read access to the entire file system. Limiting the files a Deno app can import doesn't seem to be a goal right now. But I feel that this is still a point that is worth thinking about... maybe? But I think that may be a different topic. |
What if we allowed relative imports that do not back-reference? Like, only allow relative importing of this folder and what's contained within. Or why not both, just like accessing files in a shell. Except / is the root of your project. |
I'm of the opinion that relative imports are better in general because it's much more explicit what file you want to actually import, when compared to node-style imports. That's the core reason for deno's approach here, no? While it is bothersome needing to update imports whenever moving a file, or having to figure out how many When met with the safer, simpler, more maintainable option (relative imports), relying on tooling to smooth out the DX seems like the next natural step forward. |
@kizerkizer Yes, that would be great. (I don't know if I've been clear enough. I don't want to remove or replace the possibility to use relative paths. I just think they are not enough.) @GSchrammel A predefined alias (that's what they are called in Webpack) could be a semantic alternative. The result is the same. Also the main question still applies: "What is the project scope? How is it defined?" @kingdaro
Can you explain why? In my previous comment, I just explained the opposite.
Node also only supports relative paths. Plus the module resolution thing, but that's an entire different topic. Somewhere I read also absolute paths are supported but couldn't find any information on that. I guess it's fs absolute which wouldn't be very helpful. I'm also using VS Code and I do know about these features. But I don't know if it's a good idea to tell others to just use another editor if they don't like relative import paths. Especially those who use Atom or Vim (Is it possible to add these features there? I don't know).
I have to admin, I do get this point. But on the other hand you could also say: "Tooling shouldn't be necessary to fix design flaws." The question is, which one applies here... |
I like the idea of absolute paths and I think, when done right, they could make imports more readable, as described above. But, I think that implementing them in a way that they actually make sense is a little problematic, which would largely come down to external imports. I like the idea of absolute paths being relative to the project root, which is where the entry point would always be located. However, the absolute paths for imports within external imports would have to use the imported file as their root. So, doing However, what happens, if you want to import a sub resource from say I don't see an obvious way to solve this problem, since Deno doesn't/won't have a package.json file or similar which could describe the project root. Unless, of course, the import statement would also support some sort of root flag -- which might make importing stuff more confusing... |
Since on the web If project- or cwd-based resolution is desired however, we can make this explicit in the syntax, like so: import { method } from 'project://module.ts'
import { method } from 'cwd://module.ts' When accidentally used in the browser, this will throw a much clearer 'Invalid URL scheme' style error, instead of the likely 404 you'll get when using |
Oh, wait. If you import a file via a URL this file is the only one that gets imported. There are no other files at that location that could be imported. Because of that, you should only import bundled files from external sources. But bundling is a planned feature of Deno. So I don't see a problem there. But importing external But to be honest I'm also not really sold on the " If Deno has an equivalent it could contain instructions on how to bundle your code (of course not too much). But the finished product could still be a single code file (is it supposed to be a Also updating a library is another problem. If the URL contains the imported version and the URL is used all over your project you'll have a hard time updating the version numbers without missing a spot. Otherwise, you'll end up shipping your code with two or more versions of a dependency. (And relying on tooling could be more difficult here) I just fear if Deno doesn't tackle these problems someone else will. Wasn't npm developed independently at first and got integrated with Node.js later on? Now we have npm, Yarn, bower, etc. Java has a similar problem (see above). Cargo has been part of Rust from the very beginning and everyone seems to be happy with it (= I don't know of any alternatives). I just realized something: You could still use npm with Deno: init an npm project, install your dependencies, write a global |
@brechtcs For browsers the scope gets defined by the HTTP server. Via an apache or nginx config. (But when I started developing in Node, I've realized that a mapping between a URL path and a file system path is just a "feature" of the server. The URL path is technically just a string and you can do with it whatever you want.) If this should be supported by Deno as well there of course also needs to be that kind of configuration. And there we are at a cwd relative imports are actually not a bad idea. Use cases would be CLI tools written in Deno. But then again, you need to configure some things: What commands should be available in the terminal, what files should be executed? And you need a way to register them. (If that's a planned feature at all.) |
@alinnert I don't necessarily disagree with you. My point was just that, since it's difficult to pin down the exact user expectation of what |
@brechtcs Yes, I understand. I just took your idea and developed it a little further. If we use protocols we just have to be careful not to introduce protocol clashes. Custom protocols are in heavy use recently. VSCode uses |
You mean this?
We'll just have to agree to disagree on this one. If I have a file in a project referencing another file, there can only be one possible file to import in that specific context. If you mean that there could be multiple |
@kingdaro Technically this, but mentally I was inside one project. You know of course if you're inside a different project. It's difficult to come up with a more specific example...
Both
|
I get what you mean, and I can agree that it's clearer from a human readability standpoint, but from a technical standpoint, I don't think "explicit" is the most accurate word to use here. If we look at things from the perspective of the module resolution algorithm:
Though this can be remedied with some sort of prefix system (as I think was mentioned before). Respectively, While that could bring about the complexity in module resolution this project was most likely trying to avoid, it feels like a reasonable enough compromise. EDIT: Actually, after some thought:
And the project root could be configured using something like the I'd still prefer to just use relatives, though. |
Ah, now we're on the same level. I was missing the "technical standpoint" information bit. I agree that But I'm just asking for the pure existence of this feature, the semantics were just a first thought or idea. It doesn't really matter how it gets implemented. I'm fine with any solution: prefix, protocols, pre-defined alias... |
I didn't read the whole detail of what you are talking about but on the web |
There seem to be two major concerns:
Maybe some syntactic sugar can help make the most of both?
You could have multiple basepaths but group / deduplicate as appropiate to e.g.:
|
It’s time that real namespacing is introduced to the JS world. namespace MyNamespace:
use My\Awesome\Lib; Please for the love of god make this happen. Relative imports are another can of worms. |
I can definitely appreciate keeping it simple; the speed of directly linking to third party modules in deno is very refreshing. Most of my professional experience is on large teams that maintain many apps, so my head always goes to abstraction right away. I still believe a more official solution to this problem is inevitable, but it's probably best to not hard-wire any particular solution until the ecosystem matures more |
The rational of import maps isn't that it's easier than a |
Here is an overview of the current behaviour. The last one surprised me.
🤷♂️ is the only browser deviation. JSPM also expects absolute paths to resolve like browsers do. Unless they change it. |
@thgh We should be able to support absolute path resolution. It's a little odd for local development tho because deno won't know where the root will be in a file system... |
How do browsers find |
@jedahan Yes - let's do |
Browsers don't use that. Items like AMD use XHR, and the internals of the browser know the current location when the URL is absolute. Also module resolution doesn't happen in the runtime. It is Rust that needs to know that and it does, because the request contains the referencing URL. To support it, you just need to change the module resolution logic in Rust, but I still don't think it will do what people are expecting (Or be useful). Likely someone will need/want to configure the loader, and the WHATWG has repeatedly dodged making the ability to configure the ESM loader. |
Let's just assume that on the file system, the "root" is the current working directory. If we resolve absolute paths and set |
@ry to be clear... If you run
My question is if you run |
@kitsonk I agree with those itemized examples.
I guess in that case it should be set to |
Cool... so to be clear:
|
s/arg module/main module/ |
What is the origin in this case:
If import { something } from "/otherfile.ts" Will it use If I understood correctly, if deno sets it to just host then the answer is first one. In case it sets it to the host and path, it's the second. |
I think we've reached consensus here on behavior. I will now accept implementations for abs path resolution and (I believe @kitsonk is working on this as part of his continuing compiler refactors?) |
@ry yup... probably easier taking care of it that way. |
I forgot this... I will take a look at it. We have |
I haven't read all the comments above so someone might have already mentioned this. I think there is no need to be able to import relative to the "project" root, if this is defined as the entrypoint of your application. What we should be able to do is import relative to the root of the current "module boundary" as I like to call it. In node.js this would have been relative to the root of the package you are in. With Deno, there is no concept of packages, so it would be necessary in code to be able to create a new isolated boundary. I think this is quite fundamental to module resolution in all languages / package managers. However, I understand that this is likely not possible in Deno in order to achieve compatibility with browsers. |
I guess that this is still not possible. AFAIK Typescript will limit you too You do have the option to set This is very bad for library authors, since consumers of your lib need to set the same rootDir in their own tsconfig in order for their tsc to resolve the imports. There was a issue open in the TS repo but they closed it #wontfix |
Okay, this project looks really interesting so far. While watching the talk I just noticed one thing that might be a problem for some developers. That's just allowing imports with relative path's (besides URLs). There are a lot of questions on the internet on how one can import a file in TS/Webpack/whatever relative to the project root. With relative paths people will end up with things like
import { foo } from '../../../../modules/featureA/foo.ts'
. Or was it just../../../modules/...
? What if I move my files around? Yes, you have to update your imports anyway. But figuring out how many directories you have to go up is a very tedious task on its own.In the talk, you/Ryan talked about browser compatibility. I haven't tried out ES modules in the browser just yet. But I'm pretty sure it also supports absolute paths. Absolute in that context means relative to the web root. It would be really handy if we were able to just write
import { foo } from '/modules/featureA/foo.ts'
.Of course, now there's the question: What is the root directory of a deno application? The only thing that makes sense to me right now is the folder that contains the entry file ‒ basically what
process.cwd()
is in node. But I also think it's fine to place the entry file in the most top-level directory of the project, isn't it?Or is there any problem about absolute paths I didn't think about so far? What do you think about that?
The text was updated successfully, but these errors were encountered: