mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 15:24:46 -05:00
Provide compiled JSON to TypeScript compiler. (#4404)
Fixes #4101 Previously, we would just provide the raw JSON to the TypeScript compiler worker, but TypeScript does not transform JSON. This caused a problem when emitting a bundle, that the JSON would just be "inlined" into the output, instead of being transformed into a module. This fixes this problem by providing the compiled JSON to the TypeScript compiler, so TypeScript just sees JSON as a "normal" TypeScript module.
This commit is contained in:
parent
83f4916195
commit
da8cb408c8
5 changed files with 60 additions and 7 deletions
|
@ -242,8 +242,16 @@ export class Host implements ts.CompilerHost {
|
||||||
assert(sourceFile != null);
|
assert(sourceFile != null);
|
||||||
if (!sourceFile.tsSourceFile) {
|
if (!sourceFile.tsSourceFile) {
|
||||||
assert(sourceFile.sourceCode != null);
|
assert(sourceFile.sourceCode != null);
|
||||||
|
// even though we assert the extension for JSON modules to the compiler
|
||||||
|
// is TypeScript, TypeScript internally analyses the filename for its
|
||||||
|
// extension and tries to parse it as JSON instead of TS. We have to
|
||||||
|
// change the filename to the TypeScript file.
|
||||||
sourceFile.tsSourceFile = ts.createSourceFile(
|
sourceFile.tsSourceFile = ts.createSourceFile(
|
||||||
fileName.startsWith(ASSETS) ? sourceFile.filename : fileName,
|
fileName.startsWith(ASSETS)
|
||||||
|
? sourceFile.filename
|
||||||
|
: fileName.toLowerCase().endsWith(".json")
|
||||||
|
? `${fileName}.ts`
|
||||||
|
: fileName,
|
||||||
sourceFile.sourceCode,
|
sourceFile.sourceCode,
|
||||||
languageVersion
|
languageVersion
|
||||||
);
|
);
|
||||||
|
|
|
@ -35,7 +35,10 @@ function getExtension(fileName: string, mediaType: MediaType): ts.Extension {
|
||||||
case MediaType.TSX:
|
case MediaType.TSX:
|
||||||
return ts.Extension.Tsx;
|
return ts.Extension.Tsx;
|
||||||
case MediaType.Json:
|
case MediaType.Json:
|
||||||
return ts.Extension.Json;
|
// we internally compile JSON, so what gets provided to the TypeScript
|
||||||
|
// compiler is an ES module, but in order to get TypeScript to handle it
|
||||||
|
// properly we have to pretend it is TS.
|
||||||
|
return ts.Extension.Ts;
|
||||||
case MediaType.Wasm:
|
case MediaType.Wasm:
|
||||||
// Custom marker for Wasm type.
|
// Custom marker for Wasm type.
|
||||||
return ts.Extension.Js;
|
return ts.Extension.Js;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { bold, cyan, yellow } from "../colors.ts";
|
||||||
import { CompilerOptions } from "./api.ts";
|
import { CompilerOptions } from "./api.ts";
|
||||||
import { buildBundle } from "./bundler.ts";
|
import { buildBundle } from "./bundler.ts";
|
||||||
import { ConfigureResponse, Host } from "./host.ts";
|
import { ConfigureResponse, Host } from "./host.ts";
|
||||||
import { SourceFile } from "./sourcefile.ts";
|
import { MediaType, SourceFile } from "./sourcefile.ts";
|
||||||
import { atob, TextEncoder } from "../web/text_encoding.ts";
|
import { atob, TextEncoder } from "../web/text_encoding.ts";
|
||||||
import * as compilerOps from "../ops/compiler.ts";
|
import * as compilerOps from "../ops/compiler.ts";
|
||||||
import * as util from "../util.ts";
|
import * as util from "../util.ts";
|
||||||
|
@ -51,13 +51,13 @@ function cache(
|
||||||
// NOTE: If it's a `.json` file we don't want to write it to disk.
|
// NOTE: If it's a `.json` file we don't want to write it to disk.
|
||||||
// JSON files are loaded and used by TS compiler to check types, but we don't want
|
// JSON files are loaded and used by TS compiler to check types, but we don't want
|
||||||
// to emit them to disk because output file is the same as input file.
|
// to emit them to disk because output file is the same as input file.
|
||||||
if (sf.extension === ts.Extension.Json) {
|
if (sf.mediaType === MediaType.Json) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: JavaScript files are only cached to disk if `checkJs`
|
// NOTE: JavaScript files are only cached to disk if `checkJs`
|
||||||
// option in on
|
// option in on
|
||||||
if (sf.extension === ts.Extension.Js && !checkJs) {
|
if (sf.mediaType === MediaType.JavaScript && !checkJs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,9 +136,9 @@ fn op_fetch_source_files(
|
||||||
}
|
}
|
||||||
_ => f,
|
_ => f,
|
||||||
};
|
};
|
||||||
// Special handling of Wasm files:
|
// Special handling of WASM and JSON files:
|
||||||
// compile them into JS first!
|
// compile them into JS first!
|
||||||
// This allows TS to do correct export types.
|
// This allows TS to do correct export types as well as bundles.
|
||||||
let source_code = match file.media_type {
|
let source_code = match file.media_type {
|
||||||
msg::MediaType::Wasm => {
|
msg::MediaType::Wasm => {
|
||||||
global_state
|
global_state
|
||||||
|
@ -148,6 +148,14 @@ fn op_fetch_source_files(
|
||||||
.map_err(|e| OpError::other(e.to_string()))?
|
.map_err(|e| OpError::other(e.to_string()))?
|
||||||
.code
|
.code
|
||||||
}
|
}
|
||||||
|
msg::MediaType::Json => {
|
||||||
|
global_state
|
||||||
|
.json_compiler
|
||||||
|
.compile(&file)
|
||||||
|
.await
|
||||||
|
.map_err(|e| OpError::other(e.to_string()))?
|
||||||
|
.code
|
||||||
|
}
|
||||||
_ => String::from_utf8(file.source_code).unwrap(),
|
_ => String::from_utf8(file.source_code).unwrap(),
|
||||||
};
|
};
|
||||||
Ok::<_, OpError>(json!({
|
Ok::<_, OpError>(json!({
|
||||||
|
|
|
@ -398,6 +398,40 @@ fn bundle_single_module() {
|
||||||
assert_eq!(output.stderr, b"");
|
assert_eq!(output.stderr, b"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bundle_json() {
|
||||||
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
let json_modules = util::root_path().join("cli/tests/020_json_modules.ts");
|
||||||
|
assert!(json_modules.is_file());
|
||||||
|
let t = TempDir::new().expect("tempdir fail");
|
||||||
|
let bundle = t.path().join("020_json_modules.bundle.js");
|
||||||
|
let mut deno = util::deno_cmd()
|
||||||
|
.current_dir(util::root_path())
|
||||||
|
.arg("bundle")
|
||||||
|
.arg(json_modules)
|
||||||
|
.arg(&bundle)
|
||||||
|
.spawn()
|
||||||
|
.expect("failed to spawn script");
|
||||||
|
let status = deno.wait().expect("failed to wait for the child process");
|
||||||
|
assert!(status.success());
|
||||||
|
assert!(bundle.is_file());
|
||||||
|
|
||||||
|
let output = util::deno_cmd()
|
||||||
|
.current_dir(util::root_path())
|
||||||
|
.arg("run")
|
||||||
|
.arg("--reload")
|
||||||
|
.arg(&bundle)
|
||||||
|
.output()
|
||||||
|
.expect("failed to spawn script");
|
||||||
|
// check the output of the the bundle program.
|
||||||
|
assert!(std::str::from_utf8(&output.stdout)
|
||||||
|
.unwrap()
|
||||||
|
.trim()
|
||||||
|
.ends_with("{\"foo\":{\"bar\":true,\"baz\":[\"qat\",1]}}"));
|
||||||
|
assert_eq!(output.stderr, b"");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bundle_tla() {
|
fn bundle_tla() {
|
||||||
// First we have to generate a bundle of some module that has exports.
|
// First we have to generate a bundle of some module that has exports.
|
||||||
|
|
Loading…
Reference in a new issue