I have a question about a use case involving isomorphic modules, and wondering if this has already been considered/resolved.
In a scenario where I'm writing some code that is intended to run in a browser and a server, how can I ensure that my dependencies are also isomorphic.
For example:
in https://my-code/module-a.js
import dependency from 'https://some-domain/dependency.js';
in https://some-domain/dependency.js
import anotherDependency from 'https://some-other-domain/dependency.ts';
In this example, my code will not work in a browser because my dependency is trying to import a typescript file, which doesn't work in browsers.
Besides this potential syntactical conflict, you can also expect that some modules will use server-only APIs (such as file system utilities).
In the npm+bundler method of writing isomorphic code, this is handled by giving hints to the bundlers in the package.json file (such as with browser entry).
So how are these things intended to be handled when targeting deno and browser runtimes?
There is a discussion going in #1705
@bartlomieju thanks for pointing that issue out. I think it is related but it doesn't seem to cover the problem where a dependency uses typescript. So it may make sense to keep the conversations separate 馃.
This is part of why TypeScript leaves extensions off of module specifiers, because at runtime it is never TypeScript. At the same time, all of these modules will be TypeScript and won't be usable in a browser, ever.
People are going to have to use some sort of transpiler. tsc, even with a language service plugin won't cut it though as it will still emit. Webpack, Babel, and Rollup should all be able to handle it though.
We have talked about at least a simple bundler and there is the POC around rollup in denoland/deno_std#116. I think that will ultimately be the right path, that you can easily take a module authored for Deno and output it to a browser bundle.
Potentially a huge breaking change, but I would prefer modules to be isomorphic by default and that you would need to run deno with flag(s) (e.g, --allow-ts) in order to load anything the could not run in the browser (non-http modules, typescript, file system apis, etc)
Update: I would also be okay with a non-breaking change flag such as --isomorphic-only
I want to provide a server-side solution to this by having Deno.land/x serve up generated JS at the corresponding URL..
but I would prefer modules to be isomorphic by default and that you would need to run deno with flag(s) (e.g,
--allow-ts)
I think disallowing TypeScript by default would make me want to part ways with the project pretty quickly. Isomorphic code is a bit of a fallacy that sounds great on paper but I have not seen it work effectively in practice.
There is the general compatibility of APIs and keeping them aligned is a good idea, but hobbling or dumbing down Deno to preserve that just doesn't feel right to me. I do agree there should be a frictionless way of accomplishing it though.
Serving up compiled JavaScript is a good idea, which would rewrite the module IDs to their compiled counterpart, but it doesn't fully go the way of what we should be doing with a browser though. Even with HTTP/2, there will always be a role for bundling. The cost of remote resources for a server will always be different than a browser.
I want to provide a server-side solution to this by having Deno.land/x serve up generated JS at the corresponding URL..
@ry correct me if I'm misinterpreting this but this would only solve the problem if a module depends on a library that is served by the deno.land service. Right?
Isomorphic code is a bit of a fallacy that sounds great on paper but I have not seen it work effectively in practice.
@kitsonk I don't think I agree with this statement. There are plenty of widely used libraries that are isomorphic (lodash and react are two examples). If either of these libraries only worked on the browser or the server, I don't think they would be as successful/popular as they are.
I also agree with your point about bundlers providing a solution to this problem. This is how we have been solving similar problems in recent history so I don't see anything wrong with continuing to do that. However, it begs the question, is it worth requiring that typescript is enabled via a compilation process, instead of requiring it for browser support? 馃 Posing the question because (As someone who hasn't used typescript extensively) I'm not totally sure what the benefits are of a typescript runtime (is it just to remove the compilation step?).
This conversation makes me think that the deno vision (as stated in the README) is misleading:
Aims to be browser compatible.
I understood this as having the ability to run the same code in both platforms. But it doesn't seem like it is possible to guarantee that while shipping/depending on typescript modules.
https://deno.land/manual.html#browsercompatibility
Its defined fairly exactly here
@ry thanks for that link. I had not read this document before but I agree that states the compatibility vision much more clearly.
Also agree with @akircher with having a non-breaking --isomorphic-only flag to warn against using API's that will prevent the code from working in a browser. Though I can also see this being handled with an eslint plugin.
One of the qualifiers in the above browser compatibility statement can be removed once https://github.com/denoland/deno/issues/1705 is complete - namely that there will be no special "deno" module - only a Deno global variable which may or may not be undefined.
Deno loves TypeScript and we're always going to execute it out of the box - and that's obviously not going to work out of the box in the browser. So I think we need some tooling or maybe just documentation on how people are expected to transpile. For deno_std and other modules on deno.land/x I want this done at the server-layer so that browsers can take advantage of deno_std too.
I'm not into the idea of --isomorphic-only ... but maybe we can expose something in --info to say if the code is expected to run in browsers.
Most helpful comment
Potentially a huge breaking change, but I would prefer modules to be isomorphic by default and that you would need to run deno with flag(s) (e.g,
--allow-ts) in order to load anything the could not run in the browser (non-http modules, typescript, file system apis, etc)Update: I would also be okay with a non-breaking change flag such as
--isomorphic-only