-
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
Rewrite deno_dir.rs #2057
Comments
cli/compiler's ModuleMetaData is also closely related, should that be pulled out too? I propose this be called core/cache.rs. Happy to have a stab at this. |
@hayd I think core/cache.rs is a good name. I'm not totally sure about this part "Remove the gen directory completely. Instead generated javascript and source maps should live along side their typescript counterparts." |
IMHO I want to suggest a way to purge |
I wasn’t suggesting that the generated files would be in the project directory. They’d still live in the cache directory. For example if you had /home/ry/main.ts that would map to $DENO_DIR/file/home/ry/main.js |
I didn't catch that... This approach is super clean 👍 |
For consistency would you also cp main.ts to $DENO_DIR/file/home/ry/main.ts ? That way "generated javascript and source maps should live along side their typescript counterparts" in the same way as they do for http/https. |
@hayd hmm seems superfluous... |
That's true, I agree it's a little weird, but otherwise among http/https/etc. file is going to be a special case in not having a .ts file alongside .js and .js.map... |
I've started working on progress bars for downloads and import, since downloads and compilation is async it would be helpful to store number of downloaded and compiled files on |
@bartlomieju I'd rather there be a "ProgressBar" object (which should wrap whichever progress bar crate we're using) which can be added to ThreadSafeState. Then you'd have something like |
One consideration, with CheckJS enabled (see #2114) the TypeScript compiler will transform JS->JS. While we could discard the output, it makes more sense to cache both the input and output. This would allow support of transforming many CommonJS modules and AMD modules into ES modules that can be run by Deno transparently. In that case we would have an input and output JS to cache. |
@kitsonk Although I'm not against this in the limit, I wouldn't want to tie this requirement to refactoring DenoDir. Does CheckJS output something different than the input if the input is ESM? |
To summarize my position (using suggest we've discussed here):
Goals of the new
If there are no other requirements, I welcome pseudo-code which starts specifying the interface. |
Not with our targets as they are. If we weren't supporting I guess my main point is there is always an input file and usually an output file (for example JSON imports should be transformed to an embedded |
It would be cool to support (This seems like it wouldn't be too difficult to support these days?) |
|
At @hayd are you still working on this? If not, I would like to. |
I'd like to add my 2 cents:
|
@kitsonk please take it. |
@ry and I discussed, thus should rest a little bit until bundle and import maps settle down a bit. |
Here's link to high level diagram that I created with my take on rewriting deno_dir: https://drive.google.com/file/d/1xk8e1nCWSugvbz1yOGlQQJmTDEmNJQh_/view?usp=sharing Write up with explanation for my choices and pseudo code will follow tomorrow - I need to polish it a bit. There are still some missing bits like:
Anyway feel free to take a look and comment |
Proposed implementationOverviewMain goal of rewrite is to make Rewrite requires significant changes to following files:
Data structures
DenoDirImportant goal of rewrite is to make This goal achieved via following public API:
save_source_code(
"https://deno.land/std/http/file_server.ts",
"<snip>"
);
// saves file to `$DENO_DIR/https/deno.land/std/http/file_server.ts
save_auxiliary_file(
"https://deno.land/std/http/file_server.ts",
"headers.json",
"<snip>"
);
// saves file to `$DENO_DIR/https/deno.land/std/http/file_server.ts.headers.json
save_auxiliary_file(
"file:///dev/file_server.js",
"map",
"<snip>"
);
// saves file to `$DENO_DIR/file/dev/file_server.js.map Important part of new struct ModuleMetaDataCache(Mutex<HashMap<ModuleSpecifier, ModuleMetaData>>);
impl ModuleMetaDataCache {
pub fn get(self, module_specifier) -> Option<ModuleMetaData>
pub fn cache(self, module_meta_data)
} It is a simple hash map that stores metadata for modules that have already been requested and fetched - ensuring that no file is read from disk/fetched from net more than once. This is in-process cache. MISSING BITS:
TS compiler
StateCurrently
With described approach it's possible to encapsulate TS compilation logic in small struct called impl TSCompiler {
pub fn compile(self, module_specifier) -> Future<SourceCodeInfo, DenoError> {
let compile_module_specifier = ...;
if use_cache {
let compiled_module_meta_data = await self.deno_dir.fetch_module_meta_data(compiled_module_specifier);
if !self.is_stale(compiled_module_meta_data) {
compiled_module_meta_data.into_module();
}
}
let ts_compiler = setup_compiler_worker();
let compiler_result = ts_compiler.post_message(module_specifier);
if compiler_result.error || compiler_result.diagnostics {
return DenoError::from(compiler_result)
}
let compiled_module_meta_data = await self.deno_dir.fetch_module_meta_data(compiled_module_specifier);
compiled_module_meta_data.into_module();
}
} The great thing is it can be abstracted away to supported other file types: impl JSONCompiler {
pub fn compile(self, module_specifier) -> Future<SourceCodeInfo, DenoError> {
let module_meta_data = await self.deno_dir.fetch_module_meta_data(module_specifier);
// wrap JSON source in `export default` and return `SourceCodeInfo`
{
source_dode: format!(
"export default {};",
str::from_utf8(&self.source_code).unwrap()
),
module_specifier
}
}
} Want to import Rust file in your JavaScript like in Parcel? There you go: impl RustCompiler {
pub fn compile(self, module_specifier) -> Future<SourceCodeInfo, DenoError> {
let compile_module_specifier = ...;
let module_meta_data = await self.deno_dir.fetch_module_meta_data(module_specifier);
// compile Rust file to WebAssembly
// https://github.com/parcel-bundler/parcel/blob/master/packages/core/parcel-bundler/src/assets/RustAsset.js
// wrap output WASM code similar to Parcel:
// https://github.com/parcel-bundler/parcel/blob/master/packages/core/parcel-bundler/src/builtins/loaders/browser/wasm-loader.js
}
} That means we can create something called There are probably a few details that I forgot to describe, I'll update this comment when I remember them. Please comment and ask questions. CC @ry @kitsonk @hayd @piscisaureus EDIT: Also CC @kevinkassimo |
It's very nice to have such a comprehensive analysis of the problem! I think the abstracted compiler sounds good. I'd like to have a lower-level interface to DENO_DIR which doesn't know anything about downloading/compiling or even modules. I'm not sure exactly what this would look like, but it might be something as simple as struct DenoDir2 {
location: PathBuf,
}
impl DenoDir2 {
fn set(url: Url, data: &[u8]) -> Result<()> { unimplemented!() }
fn get(url: Url) -> Result<Vec<u8>> { unimplemented!() }
} I think this could work fine with your design? |
Thanks!
Yes, that should be possible 👍 looks like it corresponds to Actually I believe it'd be possible to structure code in such a way, that allows to skip EDIT: |
@bartlomieju Looks good at first glance, will check more carefully tonight. Also would it be better if we could actually put this proposal in a Google Doc so others could add their suggestions on certain parts of the proposal (and easier to make comment threads)? |
@kevinkassimo thanks for suggestion, here's link to doc: |
@ry do you think we can close this issue now? |
deno_dir is starting to show its age, it's time for it to be redesigned from scratch. Here are some of the issues I want to address
//core
and be independent of other modules in core. deno_dir.rs is currently quite tangled up with other modules, which makes it difficult to refactor.anything else?
The text was updated successfully, but these errors were encountered: