1
1
// Copyright 2018-2025 the Deno authors. MIT license.
2
2
3
3
use std:: env;
4
- use std:: path:: PathBuf ;
5
4
6
- use deno_core:: snapshot:: * ;
7
5
use deno_runtime:: * ;
8
6
9
- mod ts {
10
- use std:: collections:: HashMap ;
11
- use std:: io:: Write ;
12
- use std:: path:: Path ;
13
- use std:: path:: PathBuf ;
14
-
15
- use deno_core:: op2;
16
- use deno_core:: v8;
17
- use deno_core:: OpState ;
18
- use deno_error:: JsErrorBox ;
19
- use serde:: Serialize ;
20
-
21
- use super :: * ;
22
-
23
- #[ derive( Debug , Serialize ) ]
24
- #[ serde( rename_all = "camelCase" ) ]
25
- struct LoadResponse {
26
- data : String ,
27
- version : String ,
28
- script_kind : i32 ,
29
- }
30
-
31
- #[ op2]
32
- #[ serde]
33
- // using the same op that is used in `tsc.rs` for loading modules and reading
34
- // files, but a slightly different implementation at build time.
35
- fn op_load (
36
- state : & mut OpState ,
37
- #[ string] load_specifier : & str ,
38
- ) -> Result < LoadResponse , JsErrorBox > {
39
- let op_crate_libs = state. borrow :: < HashMap < & str , PathBuf > > ( ) ;
40
- let path_dts = state. borrow :: < PathBuf > ( ) ;
41
- let re_asset = lazy_regex:: regex!( r"asset:/{3}lib\.(\S+)\.d\.ts" ) ;
42
-
43
- // specifiers come across as `asset:///lib.{lib_name}.d.ts` and we need to
44
- // parse out just the name so we can lookup the asset.
45
- if let Some ( caps) = re_asset. captures ( load_specifier) {
46
- if let Some ( lib) = caps. get ( 1 ) . map ( |m| m. as_str ( ) ) {
47
- // if it comes from an op crate, we were supplied with the path to the
48
- // file.
49
- let path = if let Some ( op_crate_lib) = op_crate_libs. get ( lib) {
50
- PathBuf :: from ( op_crate_lib)
51
- . canonicalize ( )
52
- . map_err ( JsErrorBox :: from_err) ?
53
- // otherwise we will generate the path ourself
54
- } else {
55
- path_dts. join ( format ! ( "lib.{lib}.d.ts" ) )
56
- } ;
57
- let data =
58
- std:: fs:: read_to_string ( path) . map_err ( JsErrorBox :: from_err) ?;
59
- return Ok ( LoadResponse {
60
- data,
61
- version : "1" . to_string ( ) ,
62
- // this corresponds to `ts.ScriptKind.TypeScript`
63
- script_kind : 3 ,
64
- } ) ;
65
- }
66
- }
67
-
68
- Err ( JsErrorBox :: new (
69
- "InvalidSpecifier" ,
70
- format ! ( "An invalid specifier was requested: {}" , load_specifier) ,
71
- ) )
72
- }
73
-
74
- deno_core:: extension!( deno_tsc,
75
- ops = [
76
- op_load,
77
- ] ,
78
- esm_entry_point = "ext:deno_tsc/99_main_compiler.js" ,
79
- esm = [
80
- dir "tsc" ,
81
- "97_ts_host.js" ,
82
- "98_lsp.js" ,
83
- "99_main_compiler.js" ,
84
- ] ,
85
- js = [
86
- dir "tsc" ,
87
- "00_typescript.js" ,
88
- ] ,
89
- options = {
90
- op_crate_libs: HashMap <& ' static str , PathBuf >,
91
- build_libs: Vec <& ' static str >,
92
- path_dts: PathBuf ,
93
- } ,
94
- state = |state, options| {
95
- state. put( options. op_crate_libs) ;
96
- state. put( options. build_libs) ;
97
- state. put( options. path_dts) ;
98
- } ,
99
- ) ;
100
-
101
- pub fn create_compiler_snapshot ( snapshot_path : PathBuf , cwd : & Path ) {
102
- // libs that are being provided by op crates.
103
- let mut op_crate_libs = HashMap :: new ( ) ;
104
- op_crate_libs. insert ( "deno.cache" , deno_cache:: get_declaration ( ) ) ;
105
- op_crate_libs. insert ( "deno.console" , deno_console:: get_declaration ( ) ) ;
106
- op_crate_libs. insert ( "deno.url" , deno_url:: get_declaration ( ) ) ;
107
- op_crate_libs. insert ( "deno.web" , deno_web:: get_declaration ( ) ) ;
108
- op_crate_libs. insert ( "deno.fetch" , deno_fetch:: get_declaration ( ) ) ;
109
- op_crate_libs. insert ( "deno.webgpu" , deno_webgpu_get_declaration ( ) ) ;
110
- op_crate_libs. insert ( "deno.websocket" , deno_websocket:: get_declaration ( ) ) ;
111
- op_crate_libs. insert ( "deno.webstorage" , deno_webstorage:: get_declaration ( ) ) ;
112
- op_crate_libs. insert ( "deno.canvas" , deno_canvas:: get_declaration ( ) ) ;
113
- op_crate_libs. insert ( "deno.crypto" , deno_crypto:: get_declaration ( ) ) ;
114
- op_crate_libs. insert (
115
- "deno.broadcast_channel" ,
116
- deno_broadcast_channel:: get_declaration ( ) ,
117
- ) ;
118
- op_crate_libs. insert ( "deno.net" , deno_net:: get_declaration ( ) ) ;
119
-
120
- // ensure we invalidate the build properly.
121
- for ( _, path) in op_crate_libs. iter ( ) {
122
- println ! ( "cargo:rerun-if-changed={}" , path. display( ) ) ;
123
- }
124
-
125
- // libs that should be loaded into the isolate before snapshotting.
126
- let libs = vec ! [
127
- // Deno custom type libraries
128
- "deno.window" ,
129
- "deno.worker" ,
130
- "deno.shared_globals" ,
131
- "deno.ns" ,
132
- "deno.unstable" ,
133
- // Deno built-in type libraries
134
- "decorators" ,
135
- "decorators.legacy" ,
136
- "dom.asynciterable" ,
137
- "dom" ,
138
- "dom.extras" ,
139
- "dom.iterable" ,
140
- "es2015.collection" ,
141
- "es2015.core" ,
142
- "es2015" ,
143
- "es2015.generator" ,
144
- "es2015.iterable" ,
145
- "es2015.promise" ,
146
- "es2015.proxy" ,
147
- "es2015.reflect" ,
148
- "es2015.symbol" ,
149
- "es2015.symbol.wellknown" ,
150
- "es2016.array.include" ,
151
- "es2016" ,
152
- "es2016.full" ,
153
- "es2016.intl" ,
154
- "es2017.arraybuffer" ,
155
- "es2017" ,
156
- "es2017.date" ,
157
- "es2017.full" ,
158
- "es2017.intl" ,
159
- "es2017.object" ,
160
- "es2017.sharedmemory" ,
161
- "es2017.string" ,
162
- "es2017.typedarrays" ,
163
- "es2018.asyncgenerator" ,
164
- "es2018.asynciterable" ,
165
- "es2018" ,
166
- "es2018.full" ,
167
- "es2018.intl" ,
168
- "es2018.promise" ,
169
- "es2018.regexp" ,
170
- "es2019.array" ,
171
- "es2019" ,
172
- "es2019.full" ,
173
- "es2019.intl" ,
174
- "es2019.object" ,
175
- "es2019.string" ,
176
- "es2019.symbol" ,
177
- "es2020.bigint" ,
178
- "es2020" ,
179
- "es2020.date" ,
180
- "es2020.full" ,
181
- "es2020.intl" ,
182
- "es2020.number" ,
183
- "es2020.promise" ,
184
- "es2020.sharedmemory" ,
185
- "es2020.string" ,
186
- "es2020.symbol.wellknown" ,
187
- "es2021" ,
188
- "es2021.full" ,
189
- "es2021.intl" ,
190
- "es2021.promise" ,
191
- "es2021.string" ,
192
- "es2021.weakref" ,
193
- "es2022.array" ,
194
- "es2022" ,
195
- "es2022.error" ,
196
- "es2022.full" ,
197
- "es2022.intl" ,
198
- "es2022.object" ,
199
- "es2022.regexp" ,
200
- "es2022.string" ,
201
- "es2023.array" ,
202
- "es2023.collection" ,
203
- "es2023" ,
204
- "es2023.full" ,
205
- "es2023.intl" ,
206
- "es2024.arraybuffer" ,
207
- "es2024.collection" ,
208
- "es2024" ,
209
- "es2024.full" ,
210
- "es2024.object" ,
211
- "es2024.promise" ,
212
- "es2024.regexp" ,
213
- "es2024.sharedmemory" ,
214
- "es2024.string" ,
215
- "es5" ,
216
- "es6" ,
217
- "esnext.array" ,
218
- "esnext.collection" ,
219
- "esnext" ,
220
- "esnext.decorators" ,
221
- "esnext.disposable" ,
222
- "esnext.full" ,
223
- "esnext.intl" ,
224
- "esnext.iterator" ,
225
- "scripthost" ,
226
- "webworker.asynciterable" ,
227
- "webworker" ,
228
- "webworker.importscripts" ,
229
- "webworker.iterable" ,
230
- ] ;
231
-
232
- let path_dts = cwd. join ( "tsc/dts" ) ;
233
- // ensure we invalidate the build properly.
234
- for name in libs. iter ( ) {
235
- println ! (
236
- "cargo:rerun-if-changed={}" ,
237
- path_dts. join( format!( "lib.{name}.d.ts" ) ) . display( )
238
- ) ;
239
- }
240
-
241
- // create a copy of the vector that includes any op crate libs to be passed
242
- // to the JavaScript compiler to build into the snapshot
243
- let mut build_libs = libs. clone ( ) ;
244
- for ( op_lib, _) in op_crate_libs. iter ( ) {
245
- build_libs. push ( op_lib. to_owned ( ) ) ;
246
- }
247
-
248
- // used in the tests to verify that after snapshotting it has the same number
249
- // of lib files loaded and hasn't included any ones lazily loaded from Rust
250
- std:: fs:: write (
251
- PathBuf :: from ( env:: var_os ( "OUT_DIR" ) . unwrap ( ) )
252
- . join ( "lib_file_names.json" ) ,
253
- serde_json:: to_string ( & build_libs) . unwrap ( ) ,
254
- )
255
- . unwrap ( ) ;
256
-
257
- // Leak to satisfy type-checker. It's okay since it's only run once for a build script.
258
- let build_libs_ = Box :: leak ( Box :: new ( build_libs. clone ( ) ) ) ;
259
- let runtime_cb = Box :: new ( |rt : & mut deno_core:: JsRuntimeForSnapshot | {
260
- let scope = & mut rt. handle_scope ( ) ;
261
-
262
- let context = scope. get_current_context ( ) ;
263
- let global = context. global ( scope) ;
264
-
265
- let name = v8:: String :: new ( scope, "snapshot" ) . unwrap ( ) ;
266
- let snapshot_fn_val = global. get ( scope, name. into ( ) ) . unwrap ( ) ;
267
- let snapshot_fn: v8:: Local < v8:: Function > =
268
- snapshot_fn_val. try_into ( ) . unwrap ( ) ;
269
- let undefined = v8:: undefined ( scope) ;
270
- let build_libs = build_libs_. clone ( ) ;
271
- let build_libs_v8 =
272
- deno_core:: serde_v8:: to_v8 ( scope, build_libs) . unwrap ( ) ;
273
-
274
- snapshot_fn
275
- . call ( scope, undefined. into ( ) , & [ build_libs_v8] )
276
- . unwrap ( ) ;
277
- } ) ;
278
-
279
- let output = create_snapshot (
280
- CreateSnapshotOptions {
281
- cargo_manifest_dir : env ! ( "CARGO_MANIFEST_DIR" ) ,
282
- startup_snapshot : None ,
283
- extensions : vec ! [ deno_tsc:: init_ops_and_esm(
284
- op_crate_libs,
285
- build_libs,
286
- path_dts,
287
- ) ] ,
288
- extension_transpiler : None ,
289
- with_runtime_cb : Some ( runtime_cb) ,
290
- skip_op_registration : false ,
291
- } ,
292
- None ,
293
- )
294
- . unwrap ( ) ;
295
-
296
- // NOTE(bartlomieju): Compressing the TSC snapshot in debug build took
297
- // ~45s on M1 MacBook Pro; without compression it took ~1s.
298
- // Thus we're not using compressed snapshot, trading off
299
- // a lot of build time for some startup time in debug build.
300
- let mut file = std:: fs:: File :: create ( snapshot_path) . unwrap ( ) ;
301
- if cfg ! ( debug_assertions) {
302
- file. write_all ( & output. output ) . unwrap ( ) ;
303
- } else {
304
- let mut vec = Vec :: with_capacity ( output. output . len ( ) ) ;
305
- vec. extend ( ( output. output . len ( ) as u32 ) . to_le_bytes ( ) ) ;
306
- vec. extend_from_slice (
307
- & zstd:: bulk:: compress ( & output. output , 22 )
308
- . expect ( "snapshot compression failed" ) ,
309
- ) ;
310
- file. write_all ( & vec) . unwrap ( ) ;
311
- }
312
-
313
- for path in output. files_loaded_during_snapshot {
314
- println ! ( "cargo:rerun-if-changed={}" , path. display( ) ) ;
315
- }
316
- }
317
- }
318
-
319
7
fn main ( ) {
320
8
// Skip building from docs.rs.
321
9
if env:: var_os ( "DOCS_RS" ) . is_some ( ) {
@@ -345,12 +33,6 @@ fn main() {
345
33
println ! ( "cargo:rustc-env=TARGET={}" , env:: var( "TARGET" ) . unwrap( ) ) ;
346
34
println ! ( "cargo:rustc-env=PROFILE={}" , env:: var( "PROFILE" ) . unwrap( ) ) ;
347
35
348
- let c = PathBuf :: from ( env:: var_os ( "CARGO_MANIFEST_DIR" ) . unwrap ( ) ) ;
349
- let o = PathBuf :: from ( env:: var_os ( "OUT_DIR" ) . unwrap ( ) ) ;
350
-
351
- let compiler_snapshot_path = o. join ( "COMPILER_SNAPSHOT.bin" ) ;
352
- ts:: create_compiler_snapshot ( compiler_snapshot_path, & c) ;
353
-
354
36
#[ cfg( target_os = "windows" ) ]
355
37
{
356
38
let mut res = winres:: WindowsResource :: new ( ) ;
@@ -362,11 +44,3 @@ fn main() {
362
44
res. compile ( ) . unwrap ( ) ;
363
45
}
364
46
}
365
-
366
- fn deno_webgpu_get_declaration ( ) -> PathBuf {
367
- let manifest_dir = std:: path:: Path :: new ( env ! ( "CARGO_MANIFEST_DIR" ) ) ;
368
- manifest_dir
369
- . join ( "tsc" )
370
- . join ( "dts" )
371
- . join ( "lib.deno_webgpu.d.ts" )
372
- }
0 commit comments