From 587f2e0800a55e58b2579758d4278a4129b609c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 1 Nov 2023 21:30:23 +0100 Subject: [PATCH] feat: precompile JSX (#20962) Co-authored-by: Marvin Hagemeister --- Cargo.lock | 4 ++-- cli/Cargo.toml | 2 +- cli/args/mod.rs | 13 ++++++----- cli/schemas/config-file.v1.json | 3 ++- cli/tests/integration/run_tests.rs | 6 +++++ .../testdata/jsx/deno-jsx-precompile.jsonc | 6 +++++ cli/tests/testdata/jsx/import-map.json | 3 ++- .../testdata/jsx/jsx-precompile/index.ts | 23 +++++++++++++++++++ .../testdata/run/jsx_precompile/no_pragma.out | 3 +++ .../testdata/run/jsx_precompile/no_pragma.tsx | 3 +++ cli/tools/repl/session.rs | 2 +- cli/tsc/99_main_compiler.js | 16 ++++++++++++- 12 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 cli/tests/testdata/jsx/deno-jsx-precompile.jsonc create mode 100644 cli/tests/testdata/jsx/jsx-precompile/index.ts create mode 100644 cli/tests/testdata/run/jsx_precompile/no_pragma.out create mode 100644 cli/tests/testdata/run/jsx_precompile/no_pragma.tsx diff --git a/Cargo.lock b/Cargo.lock index 122624d20b..f35664536d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1115,9 +1115,9 @@ dependencies = [ [[package]] name = "deno_config" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed704bc09eb4f88b26b16c75f87795d1ea1e658e26867fe684cef91c55543f1" +checksum = "0f4dd27020827a51857fbb47a21d2359f75db031e177821bff4e95368333a5a0" dependencies = [ "anyhow", "indexmap 2.0.2", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index d312209e43..c9eb3aa3ca 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -47,7 +47,7 @@ winres.workspace = true [dependencies] deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "dep_graph", "module_specifier", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] } deno_cache_dir = "=0.6.1" -deno_config = "=0.4.0" +deno_config = "=0.5.0" deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } deno_doc = { version = "=0.72.1", features = ["html"] } deno_emit = "=0.31.1" diff --git a/cli/args/mod.rs b/cli/args/mod.rs index b8b0a81f52..0778dee79b 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -114,12 +114,13 @@ pub fn ts_config_to_emit_options( "error" => deno_ast::ImportsNotUsedAsValues::Error, _ => deno_ast::ImportsNotUsedAsValues::Remove, }; - let (transform_jsx, jsx_automatic, jsx_development) = + let (transform_jsx, jsx_automatic, jsx_development, precompile_jsx) = match options.jsx.as_str() { - "react" => (true, false, false), - "react-jsx" => (true, true, false), - "react-jsxdev" => (true, true, true), - _ => (false, false, false), + "react" => (true, false, false, false), + "react-jsx" => (true, true, false, false), + "react-jsxdev" => (true, true, true, false), + "precompile" => (false, false, false, true), + _ => (false, false, false, false), }; deno_ast::EmitOptions { emit_metadata: options.emit_decorator_metadata, @@ -132,7 +133,7 @@ pub fn ts_config_to_emit_options( jsx_factory: options.jsx_factory, jsx_fragment_factory: options.jsx_fragment_factory, jsx_import_source: options.jsx_import_source, - precompile_jsx: false, + precompile_jsx, transform_jsx, var_decl_imports: false, } diff --git a/cli/schemas/config-file.v1.json b/cli/schemas/config-file.v1.json index 12ad5334c4..8e4bc75a48 100644 --- a/cli/schemas/config-file.v1.json +++ b/cli/schemas/config-file.v1.json @@ -54,7 +54,8 @@ "react", "react-jsx", "react-jsxdev", - "react-native" + "react-native", + "precompile" ] }, "jsxFactory": { diff --git a/cli/tests/integration/run_tests.rs b/cli/tests/integration/run_tests.rs index 64df31818d..61749f751d 100644 --- a/cli/tests/integration/run_tests.rs +++ b/cli/tests/integration/run_tests.rs @@ -1779,6 +1779,12 @@ itest!(jsx_import_source_pragma_import_map_dev { http_server: true, }); +itest!(jsx_import_source_precompile_import_map { + args: "run --reload --check --import-map jsx/import-map.json --no-lock --config jsx/deno-jsx-precompile.jsonc run/jsx_precompile/no_pragma.tsx", + output: "run/jsx_precompile/no_pragma.out", + http_server: true, +}); + itest!(jsx_import_source_import_map { args: "run --reload --import-map jsx/import-map.json --no-lock --config jsx/deno-jsx-import-map.jsonc run/jsx_import_source_no_pragma.tsx", output: "run/jsx_import_source_import_map.out", diff --git a/cli/tests/testdata/jsx/deno-jsx-precompile.jsonc b/cli/tests/testdata/jsx/deno-jsx-precompile.jsonc new file mode 100644 index 0000000000..95ae1b9f31 --- /dev/null +++ b/cli/tests/testdata/jsx/deno-jsx-precompile.jsonc @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "jsx": "precompile", + "jsxImportSource": "jsx-precompile" + } +} diff --git a/cli/tests/testdata/jsx/import-map.json b/cli/tests/testdata/jsx/import-map.json index baab76f209..1bfa04e2f0 100644 --- a/cli/tests/testdata/jsx/import-map.json +++ b/cli/tests/testdata/jsx/import-map.json @@ -1,6 +1,7 @@ { "imports": { "jsx/jsx-runtime": "http://localhost:4545/jsx/jsx-runtime/index.ts", - "jsx/jsx-dev-runtime": "http://localhost:4545/jsx/jsx-dev-runtime/index.ts" + "jsx/jsx-dev-runtime": "http://localhost:4545/jsx/jsx-dev-runtime/index.ts", + "jsx-precompile/jsx-runtime": "http://localhost:4545/jsx/jsx-precompile/index.ts" } } diff --git a/cli/tests/testdata/jsx/jsx-precompile/index.ts b/cli/tests/testdata/jsx/jsx-precompile/index.ts new file mode 100644 index 0000000000..0d56095e0b --- /dev/null +++ b/cli/tests/testdata/jsx/jsx-precompile/index.ts @@ -0,0 +1,23 @@ +// deno-lint-ignore-file no-explicit-any +export function jsx( + _type: any, + _props: any, + _key: any, + _source: any, + _self: any, +) {} +// deno-lint-ignore-file no-explicit-any +export const jsxAttr = (name: string, value: any) => `${name}="${value}"`; +// deno-lint-ignore-file no-explicit-any +export const jsxTemplate = (_template: string[], ..._exprs: any[]) => ""; +// deno-lint-ignore-file no-explicit-any +export const jsxEscape = (_value: any) => ""; +console.log("imported", import.meta.url); + +declare global { + namespace JSX { + interface IntrinsicElements { + [tagName: string]: Record; + } + } +} diff --git a/cli/tests/testdata/run/jsx_precompile/no_pragma.out b/cli/tests/testdata/run/jsx_precompile/no_pragma.out new file mode 100644 index 0000000000..4379959230 --- /dev/null +++ b/cli/tests/testdata/run/jsx_precompile/no_pragma.out @@ -0,0 +1,3 @@ +Download http://localhost:4545/jsx/jsx-precompile/index.ts +Check file:///[WILDCARD]/run/jsx_precompile/no_pragma.tsx +imported http://localhost:4545/jsx/jsx-precompile/index.ts diff --git a/cli/tests/testdata/run/jsx_precompile/no_pragma.tsx b/cli/tests/testdata/run/jsx_precompile/no_pragma.tsx new file mode 100644 index 0000000000..7ba21d80d2 --- /dev/null +++ b/cli/tests/testdata/run/jsx_precompile/no_pragma.tsx @@ -0,0 +1,3 @@ +export function A() { + return

hello

; +} diff --git a/cli/tools/repl/session.rs b/cli/tools/repl/session.rs index 66a39cd892..65f45652d3 100644 --- a/cli/tools/repl/session.rs +++ b/cli/tools/repl/session.rs @@ -589,12 +589,12 @@ impl ReplSession { inline_sources: false, imports_not_used_as_values: ImportsNotUsedAsValues::Preserve, transform_jsx: true, + precompile_jsx: false, jsx_automatic: false, jsx_development: false, jsx_factory: self.jsx.factory.clone(), jsx_fragment_factory: self.jsx.frag_factory.clone(), jsx_import_source: None, - precompile_jsx: false, var_decl_imports: true, })? .text; diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js index a2079c01ed..4c750cfe7a 100644 --- a/cli/tsc/99_main_compiler.js +++ b/cli/tsc/99_main_compiler.js @@ -862,12 +862,25 @@ delete Object.prototype.__proto__; } } + /** @param {Record} config */ + function normalizeConfig(config) { + // the typescript compiler doesn't know about the precompile + // transform at the moment, so just tell it we're using react-jsx + if (config.jsx === "precompile") { + config.jsx = "react-jsx"; + } + return config; + } + /** The API that is called by Rust when executing a request. * @param {Request} request */ function exec({ config, debug: debugFlag, rootNames, localOnly }) { setLogDebug(debugFlag, "TS"); performanceStart(); + + config = normalizeConfig(config); + if (logDebug) { debug(">>> exec start", { rootNames }); debug(config); @@ -983,8 +996,9 @@ delete Object.prototype.__proto__; return respond(id, true); } case "$configure": { + const config = normalizeConfig(args[0]); const { options, errors } = ts - .convertCompilerOptionsFromJson(args[0], ""); + .convertCompilerOptionsFromJson(config, ""); Object.assign(options, { allowNonTsExtensions: true, allowImportingTsExtensions: true,