diff --git a/.flowconfig b/.flowconfig index 0f356aceae5..5f8e969f2bd 100644 --- a/.flowconfig +++ b/.flowconfig @@ -36,4 +36,4 @@ untyped-import untyped-type-import [version] -0.153.0 +0.158.0 diff --git a/Cargo.lock b/Cargo.lock index c81c09b5edc..72961081c26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,29 @@ dependencies = [ "regex", ] +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] +name = "ahash" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +dependencies = [ + "getrandom 0.2.3", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.18" @@ -21,11 +44,20 @@ dependencies = [ "memchr", ] +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + [[package]] name = "anyhow" -version = "1.0.41" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61" +checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf" [[package]] name = "arrayvec" @@ -76,11 +108,17 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" @@ -91,12 +129,24 @@ dependencies = [ "generic-array", ] +[[package]] +name = "build_const" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" + [[package]] name = "bumpalo" version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" +[[package]] +name = "bytemuck" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" + [[package]] name = "byteorder" version = "1.4.3" @@ -105,9 +155,12 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" +checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" +dependencies = [ + "jobserver", +] [[package]] name = "cfg-if" @@ -121,6 +174,58 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim 0.8.0", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "cloudflare-zlib" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cfcefb5df07f146eb15756342a135eb7d76b8bb609eff9c111f7539d060f94d" +dependencies = [ + "cloudflare-zlib-sys", +] + +[[package]] +name = "cloudflare-zlib-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2040b6d1edfee6d75f172d81e2d2a7807534f3f294ce18184c70e7bb0105cd6f" +dependencies = [ + "cc", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "cpufeatures" version = "0.1.5" @@ -130,6 +235,83 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +dependencies = [ + "build_const", +] + +[[package]] +name = "crc" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10c2722795460108a7872e1cd933a85d6ec38abc4baecad51028f702da28889f" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if 1.0.0", + "lazy_static", +] + [[package]] name = "darling" version = "0.10.2" @@ -150,7 +332,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.9.3", "syn", ] @@ -181,6 +363,16 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" +[[package]] +name = "deflate" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +dependencies = [ + "adler32", + "byteorder", +] + [[package]] name = "digest" version = "0.9.0" @@ -214,6 +406,18 @@ dependencies = [ "syn", ] +[[package]] +name = "filetime" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "winapi", +] + [[package]] name = "fnv" version = "1.0.7" @@ -275,14 +479,31 @@ checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", ] +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + [[package]] name = "hashbrown" -version = "0.9.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "hermit-abi" @@ -316,14 +537,30 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f7280c75fb2e2fc47080ec80ccc481376923acb04501957fc38f935c3de5088" +[[package]] +name = "image" +version = "0.23.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-iter", + "num-rational", + "num-traits", + "png", +] + [[package]] name = "indexmap" -version = "1.6.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg", "hashbrown", + "rayon", ] [[package]] @@ -348,6 +585,15 @@ dependencies = [ "syn", ] +[[package]] +name = "itertools" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.7" @@ -375,6 +621,15 @@ dependencies = [ "libc", ] +[[package]] +name = "jobserver" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.49" @@ -415,9 +670,27 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.97" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" + +[[package]] +name = "libdeflate-sys" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" +checksum = "09c81cf7b5510a30d8a1149dcca5fe85715475a05092c786e660edc72dbf24e4" +dependencies = [ + "cc", +] + +[[package]] +name = "libdeflater" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11c0c8321257b64709e8ee6811d0b4a2ce030806e7ce1f36094bfa2c1de1540" +dependencies = [ + "libdeflate-sys", +] [[package]] name = "libmimalloc-sys" @@ -439,9 +712,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" @@ -449,6 +722,15 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + [[package]] name = "mimalloc" version = "0.1.26" @@ -458,11 +740,42 @@ dependencies = [ "libmimalloc-sys", ] +[[package]] +name = "miniz_oxide" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +dependencies = [ + "adler32", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "mozjpeg-sys" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d2d207e7338a9a58abfc8a9d247bc9cc42a1b3eaa0a4e7014272825a00015a2" +dependencies = [ + "cc", + "dunce", + "libc", + "nasm-rs", +] + [[package]] name = "napi" -version = "1.7.5" +version = "1.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59cd02f5de365f9bd6e85f1d11176a9ea70ff63ce55ea4412cb4e00fd5a0fe6c" +checksum = "eb22375ec7cbd8bee4535126bb323e4e62cbf8088d84f0225d4d3226d1619bd5" dependencies = [ "napi-sys", "serde", @@ -493,6 +806,15 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43563506c466587478849d80f46383d859b91bbec586580dadeb3639588f2f7e" +[[package]] +name = "nasm-rs" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dbff86bd2ee8cb407e8608e2c3504412a967c06286ef7e5cf7c1b9db756f0a9" +dependencies = [ + "rayon", +] + [[package]] name = "new_debug_unreachable" version = "1.0.4" @@ -530,6 +852,28 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.14" @@ -563,9 +907,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "ordered-float" -version = "2.5.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f100fcfb41e5385e0991f74981732049f9b896821542a219420491046baafdc2" +checksum = "039f02eb0f69271f26abe3202189275d7aa2258b903cb0281b5de710a2570ff3" dependencies = [ "num-traits", ] @@ -579,6 +923,33 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "oxipng" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99ac0770862c1f005398661faea0a1e8d6bb73ca2671a2eed7448d910388f97b" +dependencies = [ + "bit-vec", + "byteorder", + "clap", + "cloudflare-zlib", + "crc 2.0.0", + "crossbeam-channel", + "filetime", + "image", + "indexmap", + "itertools", + "libdeflater", + "log", + "miniz_oxide 0.4.4", + "rayon", + "rgb", + "rustc_version 0.4.0", + "stderrlog", + "wild", + "zopfli", +] + [[package]] name = "parcel-fs-search" version = "0.1.0" @@ -598,6 +969,18 @@ dependencies = [ "xxhash-rust", ] +[[package]] +name = "parcel-image" +version = "0.1.0" +dependencies = [ + "libc", + "mozjpeg-sys", + "napi", + "napi-build", + "napi-derive", + "oxipng", +] + [[package]] name = "parcel-js-swc-core" version = "0.1.0" @@ -713,6 +1096,18 @@ dependencies = [ "syn", ] +[[package]] +name = "png" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +dependencies = [ + "bitflags", + "crc32fast", + "deflate", + "miniz_oxide 0.3.7", +] + [[package]] name = "ppv-lite86" version = "0.2.10" @@ -733,9 +1128,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" dependencies = [ "unicode-xid", ] @@ -755,7 +1150,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.16", "libc", "rand_chacha", "rand_core", @@ -779,7 +1174,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.16", ] [[package]] @@ -800,6 +1195,40 @@ dependencies = [ "rand_core", ] +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.5.4" @@ -823,13 +1252,31 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9c17925a9027d298a4603d286befe3f9dc0e8ed02523141914eb628798d6e5b" +[[package]] +name = "rgb" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fddb3b23626145d1776addfc307e1a1851f60ef6ca64f376bcb889697144cf0" +dependencies = [ + "bytemuck", +] + [[package]] name = "rustc_version" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver", + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.4", ] [[package]] @@ -853,6 +1300,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "semver" version = "0.9.0" @@ -863,6 +1316,12 @@ dependencies = [ "serde", ] +[[package]] +name = "semver" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" + [[package]] name = "semver-parser" version = "0.7.0" @@ -871,9 +1330,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.126" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" dependencies = [ "serde_derive", ] @@ -901,9 +1360,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.126" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" dependencies = [ "proc-macro2", "quote", @@ -912,9 +1371,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" dependencies = [ "itoa", "ryu", @@ -923,9 +1382,9 @@ dependencies = [ [[package]] name = "sha-1" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4cfa741c5832d0ef7fab46cabed29c2aae926db0b11bb2069edd8db5e64e16" +checksum = "1a0c8611594e2ab4ebbf06ec7cbbf0a99450b8570e96cbf5188b5d5f6ef18d81" dependencies = [ "block-buffer", "cfg-if 1.0.0", @@ -936,9 +1395,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27" +checksum = "729a25c17d72b06c68cb47955d44fda88ad2d3e7d77e025663fdd69b93dd71a1" [[package]] name = "smallvec" @@ -956,7 +1415,7 @@ dependencies = [ "if_chain", "lazy_static", "regex", - "rustc_version", + "rustc_version 0.2.3", "serde", "serde_json", "url", @@ -996,6 +1455,19 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "stderrlog" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a53e2eff3e94a019afa6265e8ee04cb05b9d33fe9f5078b14e4e391d155a38" +dependencies = [ + "atty", + "chrono", + "log", + "termcolor", + "thread_local", +] + [[package]] name = "string_cache" version = "0.8.1" @@ -1034,6 +1506,12 @@ dependencies = [ "syn", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "strsim" version = "0.9.3" @@ -1052,10 +1530,11 @@ dependencies = [ [[package]] name = "swc_common" -version = "0.10.21" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "526ac4386aca6a792d75bb3bd5cb72eb170e2029f4ce0f6a9d280923da4b0ce8" +checksum = "0fc89b8c9f2fa3fc646e7d1a05ebc2063b1396b3ba5277afc741505bd7414fff" dependencies = [ + "ahash", "ast_node", "atty", "cfg-if 0.1.10", @@ -1078,9 +1557,9 @@ dependencies = [ [[package]] name = "swc_ecma_ast" -version = "0.47.0" +version = "0.49.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab98b7f6777222431bdf193bbfc6046af53cc105c8702390a9109d1a4511329b" +checksum = "3efef728f69665d765c52b233155dcb3290424f56a9f978ecfbd53f136804461" dependencies = [ "is-macro", "num-bigint", @@ -1092,9 +1571,9 @@ dependencies = [ [[package]] name = "swc_ecma_codegen" -version = "0.60.1" +version = "0.67.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e84b5477973503f94c6a82f02bc6008c148dc3dd5b07bb81fee6f5f93e3a190" +checksum = "96a380bd935ce811c0bc8b961abc97cbf3a8c759213634aa59f5b0601162ba4e" dependencies = [ "bitflags", "num-bigint", @@ -1121,12 +1600,16 @@ dependencies = [ [[package]] name = "swc_ecma_loader" -version = "0.9.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d234e6348de8d954334700f65a35485363de082fd58671c07f060f1fa499f59c" +checksum = "2bc6a797d2df5f60cc9ab6a85aa7a49ab1bcaac8150d184f79a27deba2d21983" dependencies = [ "anyhow", + "dashmap", + "fxhash", + "log", "normpath", + "once_cell", "serde", "serde_json", "swc_atoms", @@ -1137,9 +1620,9 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "0.61.1" +version = "0.67.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82ed9b5648252851ae2cfc066717fcae9c5561be74f496eda64afc791d9b17ed" +checksum = "e0418c8dcb041d74e90c2179290bf3be0e58f2425d1f86843a5e297a13755912" dependencies = [ "either", "enum_kind", @@ -1158,15 +1641,15 @@ dependencies = [ [[package]] name = "swc_ecma_preset_env" -version = "0.27.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "538902691c3a274a6e80ce7860c91b96977ebd977e1ca7fba77057e425267951" +checksum = "283a609ec84132c2751bdee13a7a81228007206538ef09a1066163602f0d34d8" dependencies = [ "dashmap", "fxhash", "indexmap", "once_cell", - "semver", + "semver 0.9.0", "serde", "serde_json", "st-map", @@ -1182,9 +1665,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms" -version = "0.57.0" +version = "0.67.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd060899f0cb2994ad9d2c04475e30864549e80dde35a526acdf3a79ec8d722" +checksum = "9c50b45538663ae18d56768c93567312dd5cbf29786678a94cfa610172ba93a4" dependencies = [ "swc_atoms", "swc_common", @@ -1204,9 +1687,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_base" -version = "0.20.1" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311b66839a94ea620382ecadb46c001132c21ad15b13f0e04ffe3ad115a8ce78" +checksum = "b5de480c55ae93eb59715cfc8f66965d192bc62cd4c12e33cff9f940f9431e12" dependencies = [ "fxhash", "once_cell", @@ -1223,9 +1706,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_classes" -version = "0.6.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9f7417ff08dd6da5bf7ab96e96bb6ae43cdf484235ded9855d5260011cc0186" +checksum = "cdcbad381d349cbff95f7602bf2d9ad6a40c7df92a391d4af62221bd0d7633a2" dependencies = [ "swc_atoms", "swc_common", @@ -1237,9 +1720,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_compat" -version = "0.23.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f464846be30234400767c1f7785bdfd2d27fef6f3cfb9f4e24a2044c9e8e76d2" +checksum = "4cca0020d15ecb278fcdc4cd55f199f39e0c42ceb9e7f9740416f36120c17ad5" dependencies = [ "arrayvec", "fxhash", @@ -1274,9 +1757,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_module" -version = "0.24.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22c79be4775f2f6f166c7901706e5cc64cd837e6a26b8f0d7ced224321a39dc2" +checksum = "ac0abb8acb4b72d1ef37971b0bfed8e267ecaab37b3d34bac96205d7b62689e2" dependencies = [ "Inflector", "anyhow", @@ -1296,9 +1779,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_optimization" -version = "0.27.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422f1a381ee1782fa5b3d883fb01239e9bca26515932b93e4fa3e956275c684f" +checksum = "fb3b4c8d2613ce06be5cf8160159eb468117ef6257eba744e1bf18125cca31ad" dependencies = [ "dashmap", "fxhash", @@ -1318,9 +1801,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_proposal" -version = "0.24.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90a18d71bee10a061894ff92d36fcc54e43197c92f70cdb98309021bff282290" +checksum = "02a8edf26ee1695c0137a829dbb8bb3c6681c1ae55e23ff45e0e0f41308e795f" dependencies = [ "either", "fxhash", @@ -1338,9 +1821,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_react" -version = "0.25.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e2bf91bc9166722159d919cff5dc0276fd404031c53a0f5c6716fdcdcb3a0a" +checksum = "72eabb27291ac7bef4f1f85e3aa7d335138dde1a1606b7d584e7f414882e5f3c" dependencies = [ "base64 0.13.0", "dashmap", @@ -1361,9 +1844,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_typescript" -version = "0.26.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d642e21c1088a040e680e81527a7d7528c3703070d15f93cc56cce7c8591f2" +checksum = "dc043fd29ceac49f13c1c994ba784f404cca3e189dd6cb771bfe905a0f776592" dependencies = [ "fxhash", "serde", @@ -1378,9 +1861,9 @@ dependencies = [ [[package]] name = "swc_ecma_utils" -version = "0.38.0" +version = "0.41.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db19d40a76ba6c01ebbbd73981645dd2552cdbfc14605481c7a9b7f6f26bd20e" +checksum = "50bacaf860e4224e1a12bea8730c94de28f990f92685dad57aa572e3473043f7" dependencies = [ "once_cell", "scoped-tls", @@ -1393,9 +1876,9 @@ dependencies = [ [[package]] name = "swc_ecma_visit" -version = "0.33.0" +version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ad83badbeda1123290a73ca6254158ed027f72f1b593f96acddcaed5d49c6a" +checksum = "d51ce688b7c984d0325261edb3ced4195790c7ac76982e269d2114ec04e3ae7c" dependencies = [ "num-bigint", "swc_atoms", @@ -1406,9 +1889,9 @@ dependencies = [ [[package]] name = "swc_ecmascript" -version = "0.43.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55e1c5047fe3f5a6c301a312c278ac018789ba4a6e40e556612e82defda422c" +checksum = "e41615d9e65c7b148950211dacd0b2343a646d84493b9c8efa8795ee1a6e2f4f" dependencies = [ "swc_ecma_ast", "swc_ecma_codegen", @@ -1444,9 +1927,9 @@ dependencies = [ [[package]] name = "swc_visit" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583cfe83f6002e1118559308b88181f34b5936b403b72548cd0259bfcf0ca39e" +checksum = "a423caa0b4585118164dbad8f1ad52b592a9a9370b25decc4d84c6b4309132c0" dependencies = [ "either", "swc_visit_macros", @@ -1486,11 +1969,39 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "tinyvec" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" +checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338" dependencies = [ "tinyvec_macros", ] @@ -1501,6 +2012,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +[[package]] +name = "typed-arena" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d" + [[package]] name = "typenum" version = "1.13.0" @@ -1509,12 +2026,9 @@ checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" [[package]] name = "unicode-bidi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" -dependencies = [ - "matches", -] +checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" [[package]] name = "unicode-normalization" @@ -1555,6 +2069,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version_check" version = "0.9.3" @@ -1578,6 +2098,12 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + [[package]] name = "wasm-bindgen" version = "0.2.72" @@ -1632,6 +2158,15 @@ version = "0.2.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7148f4696fb4960a346eaa60bbfb42a1ac4ebba21f750f75fc1375b098d5ffa" +[[package]] +name = "wild" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "035793abb854745033f01a07647a79831eba29ec0be377205f2a25b0aa830020" +dependencies = [ + "glob", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1668,3 +2203,15 @@ name = "xxhash-rust" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e575e15bedf6e57b5c2d763ffc6c3c760143466cbd09d762d539680ab5992ded" + +[[package]] +name = "zopfli" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4079b79464426ade2a1b0177fb0ce8396ba6b4084267407e333573c666073964" +dependencies = [ + "adler32", + "byteorder", + "crc 1.8.1", + "typed-arena", +] diff --git a/Cargo.toml b/Cargo.toml index 64c1cb178a8..7e966f6ac6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,5 @@ members = [ "packages/transformers/js/wasm", "packages/utils/fs-search", "packages/utils/hash", + "packages/optimizers/image" ] diff --git a/flow-libs/posthtml.js.flow b/flow-libs/posthtml.js.flow index 6e4f38c8930..ed5df61a951 100644 --- a/flow-libs/posthtml.js.flow +++ b/flow-libs/posthtml.js.flow @@ -21,8 +21,8 @@ declare module 'posthtml' { declare type PostHTMLTree = Array; declare type PostHTMLOptions = { - sync: Boolean, - skipParse: Boolean, + sync?: Boolean, + skipParse?: Boolean, ... }; declare type PostHTMLMessage = { diff --git a/flow-typed/npm/typescript_v3.3.x.js b/flow-typed/npm/typescript_v3.3.x.js index d32a41cac8c..0cef41fc841 100644 --- a/flow-typed/npm/typescript_v3.3.x.js +++ b/flow-typed/npm/typescript_v3.3.x.js @@ -1,5 +1,5 @@ -// flow-typed signature: 8ef93f972fa1514991dd699880b244bf -// flow-typed version: 80b11313ee/typescript_v3.3.x/flow_>=v0.104.x +// flow-typed signature: 1cfd67767aab1e3b8debc8321518b5a0 +// flow-typed version: 3069537731/typescript_v3.3.x/flow_>=v0.104.x declare module "typescript" { declare var versionMajorMinor: "3.3"; // "3.3"; @@ -8444,7 +8444,7 @@ declare module "typescript" { +getProjectReferences?: () => $ReadOnlyArray | void, +getLocalizedDiagnosticMessages?: () => any, +getCancellationToken?: () => HostCancellationToken, - getCurrentDirectory(): string, + +getCurrentDirectory: () => string, getDefaultLibFileName(options: CompilerOptions): string, +log?: (s: string) => void, +trace?: (s: string) => void, diff --git a/package.json b/package.json index d38ce40c38f..e2e43da8ed5 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "cross-env": "^7.0.0", "doctoc": "^1.4.0", "eslint": "^7.20.0", - "flow-bin": "0.153.0", + "flow-bin": "0.158.0", "glob": "^7.1.6", "gulp": "^4.0.2", "gulp-babel": "^8.0.0", diff --git a/packages/compressors/brotli/package.json b/packages/compressors/brotli/package.json new file mode 100644 index 00000000000..e295cbcf171 --- /dev/null +++ b/packages/compressors/brotli/package.json @@ -0,0 +1,25 @@ +{ + "name": "@parcel/compressor-brotli", + "version": "2.0.0-rc.0", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "repository": { + "type": "git", + "url": "https://github.com/parcel-bundler/parcel.git" + }, + "main": "lib/BrotliCompressor.js", + "source": "src/BrotliCompressor.js", + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.0.0-beta.1" + }, + "dependencies": { + "@parcel/plugin": "2.0.0-rc.0" + } +} diff --git a/packages/compressors/brotli/src/BrotliCompressor.js b/packages/compressors/brotli/src/BrotliCompressor.js new file mode 100644 index 00000000000..b74771dcec5 --- /dev/null +++ b/packages/compressors/brotli/src/BrotliCompressor.js @@ -0,0 +1,12 @@ +// @flow +import {Compressor} from '@parcel/plugin'; +import zlib from 'zlib'; + +export default (new Compressor({ + compress({stream}) { + return { + stream: stream.pipe(zlib.createBrotliCompress()), + type: 'br', + }; + }, +}): Compressor); diff --git a/packages/compressors/gzip/package.json b/packages/compressors/gzip/package.json new file mode 100644 index 00000000000..c0659f8d69a --- /dev/null +++ b/packages/compressors/gzip/package.json @@ -0,0 +1,25 @@ +{ + "name": "@parcel/compressor-gzip", + "version": "2.0.0-rc.0", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "repository": { + "type": "git", + "url": "https://github.com/parcel-bundler/parcel.git" + }, + "main": "lib/GzipCompressor.js", + "source": "src/GzipCompressor.js", + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.0.0-beta.1" + }, + "dependencies": { + "@parcel/plugin": "2.0.0-rc.0" + } +} diff --git a/packages/compressors/gzip/src/GzipCompressor.js b/packages/compressors/gzip/src/GzipCompressor.js new file mode 100644 index 00000000000..4e99328f39d --- /dev/null +++ b/packages/compressors/gzip/src/GzipCompressor.js @@ -0,0 +1,12 @@ +// @flow +import {Compressor} from '@parcel/plugin'; +import zlib from 'zlib'; + +export default (new Compressor({ + compress({stream}) { + return { + stream: stream.pipe(zlib.createGzip()), + type: 'gz', + }; + }, +}): Compressor); diff --git a/packages/compressors/raw/package.json b/packages/compressors/raw/package.json new file mode 100644 index 00000000000..9d73543c7a8 --- /dev/null +++ b/packages/compressors/raw/package.json @@ -0,0 +1,25 @@ +{ + "name": "@parcel/compressor-raw", + "version": "2.0.0-rc.0", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "repository": { + "type": "git", + "url": "https://github.com/parcel-bundler/parcel.git" + }, + "main": "lib/RawCompressor.js", + "source": "src/RawCompressor.js", + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.0.0-beta.1" + }, + "dependencies": { + "@parcel/plugin": "2.0.0-rc.0" + } +} diff --git a/packages/compressors/raw/src/RawCompressor.js b/packages/compressors/raw/src/RawCompressor.js new file mode 100644 index 00000000000..988b383cd5c --- /dev/null +++ b/packages/compressors/raw/src/RawCompressor.js @@ -0,0 +1,8 @@ +// @flow +import {Compressor} from '@parcel/plugin'; + +export default (new Compressor({ + compress({stream}) { + return {stream}; + }, +}): Compressor); diff --git a/packages/configs/default/index.json b/packages/configs/default/index.json index cd283904975..4c3da0c9b3f 100644 --- a/packages/configs/default/index.json +++ b/packages/configs/default/index.json @@ -40,29 +40,36 @@ "style:*.vue": ["@parcel/transformer-vue"], "custom:*.vue": ["@parcel/transformer-vue"], "*.{png,jpg,jpeg,webp}": ["@parcel/transformer-image"], + "*.svg": ["@parcel/transformer-svg"], "url:*": ["...", "@parcel/transformer-raw"] }, "namers": ["@parcel/namer-default"], "runtimes": [ "@parcel/runtime-js", "@parcel/runtime-browser-hmr", - "@parcel/runtime-react-refresh" + "@parcel/runtime-react-refresh", + "@parcel/runtime-service-worker" ], "optimizers": { "data-url:*": ["...", "@parcel/optimizer-data-url"], "*.css": ["@parcel/optimizer-cssnano"], "*.html": ["@parcel/optimizer-htmlnano"], "*.{js,mjs,cjs}": ["@parcel/optimizer-terser"], - "*.svg": ["@parcel/optimizer-svgo"] + "*.svg": ["@parcel/optimizer-svgo"], + "*.{jpg,jpeg,png}": ["@parcel/optimizer-image"] }, "packagers": { "*.html": "@parcel/packager-html", "*.css": "@parcel/packager-css", "*.{js,mjs,cjs}": "@parcel/packager-js", + "*.svg": "@parcel/packager-svg", "*.ts": "@parcel/packager-ts", - "*.{jsonld,webmanifest}": "@parcel/packager-raw-url", + "*.{jsonld,svg,webmanifest}": "@parcel/packager-raw-url", "*": "@parcel/packager-raw" }, + "compressors": { + "*": ["@parcel/compressor-raw"] + }, "resolvers": ["@parcel/resolver-default"], "reporters": ["@parcel/reporter-dev-server"] } diff --git a/packages/configs/default/package.json b/packages/configs/default/package.json index 0eacdc81a48..d09148de533 100644 --- a/packages/configs/default/package.json +++ b/packages/configs/default/package.json @@ -19,29 +19,35 @@ }, "dependencies": { "@parcel/bundler-default": "2.0.0-rc.0", + "@parcel/compressor-raw": "2.0.0-rc.0", "@parcel/namer-default": "2.0.0-rc.0", "@parcel/optimizer-cssnano": "2.0.0-rc.0", "@parcel/optimizer-htmlnano": "2.0.0-rc.0", + "@parcel/optimizer-image": "2.0.0-rc.0", "@parcel/optimizer-svgo": "2.0.0-rc.0", "@parcel/optimizer-terser": "2.0.0-rc.0", "@parcel/packager-css": "2.0.0-rc.0", "@parcel/packager-html": "2.0.0-rc.0", "@parcel/packager-js": "2.0.0-rc.0", "@parcel/packager-raw": "2.0.0-rc.0", + "@parcel/packager-svg": "2.0.0-rc.0", "@parcel/reporter-dev-server": "2.0.0-rc.0", "@parcel/resolver-default": "2.0.0-rc.0", "@parcel/runtime-browser-hmr": "2.0.0-rc.0", "@parcel/runtime-js": "2.0.0-rc.0", "@parcel/runtime-react-refresh": "2.0.0-rc.0", + "@parcel/runtime-service-worker": "2.0.0-rc.0", "@parcel/transformer-babel": "2.0.0-rc.0", "@parcel/transformer-css": "2.0.0-rc.0", "@parcel/transformer-html": "2.0.0-rc.0", + "@parcel/transformer-image": "2.0.0-rc.0", "@parcel/transformer-js": "2.0.0-rc.0", "@parcel/transformer-json": "2.0.0-rc.0", "@parcel/transformer-postcss": "2.0.0-rc.0", "@parcel/transformer-posthtml": "2.0.0-rc.0", "@parcel/transformer-raw": "2.0.0-rc.0", - "@parcel/transformer-react-refresh-wrap": "2.0.0-rc.0" + "@parcel/transformer-react-refresh-wrap": "2.0.0-rc.0", + "@parcel/transformer-svg": "2.0.0-rc.0" }, "parcelDependencies": { "@parcel/optimizer-data-url": "2.0.0-rc.0", @@ -51,7 +57,6 @@ "@parcel/transformer-elm": "2.0.0-rc.0", "@parcel/transformer-glsl": "2.0.0-rc.0", "@parcel/transformer-graphql": "2.0.0-rc.0", - "@parcel/transformer-image": "2.0.0-rc.0", "@parcel/transformer-inline-string": "2.0.0-rc.0", "@parcel/transformer-jsonld": "2.0.0-rc.0", "@parcel/transformer-less": "2.0.0-rc.0", diff --git a/packages/core/cache/src/LMDBCache.js b/packages/core/cache/src/LMDBCache.js index 7ca0c1a70db..747ad49ad73 100644 --- a/packages/core/cache/src/LMDBCache.js +++ b/packages/core/cache/src/LMDBCache.js @@ -25,6 +25,10 @@ export class LMDBCache implements Cache { }); } + ensure(): Promise { + return Promise.resolve(); + } + serialize(): {|dir: FilePath|} { return { dir: this.dir, diff --git a/packages/core/cache/src/types.js b/packages/core/cache/src/types.js index 2c806bab4ac..5f591388048 100644 --- a/packages/core/cache/src/types.js +++ b/packages/core/cache/src/types.js @@ -2,7 +2,7 @@ import type {Readable} from 'stream'; export interface Cache { - +ensure?: () => Promise; + ensure(): Promise; has(key: string): Promise; get(key: string): Promise; set(key: string, value: mixed): Promise; diff --git a/packages/core/core/index.d.ts b/packages/core/core/index.d.ts index b900d395030..5da6802752e 100644 --- a/packages/core/core/index.d.ts +++ b/packages/core/core/index.d.ts @@ -2,7 +2,7 @@ import type {InitialParcelOptions, BuildEvent, BuildSuccessEvent, AsyncSubscript import type {FarmOptions} from '@parcel/workers'; import type WorkerFarm from '@parcel/workers'; -declare class Parcel { +export default class Parcel { constructor(options: InitialParcelOptions); run(): Promise; watch( diff --git a/packages/core/core/package.json b/packages/core/core/package.json index 2dcc08ea3d8..bd76f26b6d5 100644 --- a/packages/core/core/package.json +++ b/packages/core/core/package.json @@ -28,11 +28,12 @@ "@parcel/diagnostic": "2.0.0-rc.0", "@parcel/events": "2.0.0-rc.0", "@parcel/fs": "2.0.0-rc.0", + "@parcel/graph": "2.0.0-rc.0", "@parcel/hash": "2.0.0-rc.0", "@parcel/logger": "2.0.0-rc.0", "@parcel/package-manager": "2.0.0-rc.0", "@parcel/plugin": "2.0.0-rc.0", - "@parcel/source-map": "2.0.0-rc.6", + "@parcel/source-map": "2.0.0-rc.7", "@parcel/types": "2.0.0-rc.0", "@parcel/utils": "2.0.0-rc.0", "@parcel/workers": "2.0.0-rc.0", diff --git a/packages/core/core/src/AssetGraph.js b/packages/core/core/src/AssetGraph.js index 33bedd5bcd4..6c2f1e93523 100644 --- a/packages/core/core/src/AssetGraph.js +++ b/packages/core/core/src/AssetGraph.js @@ -1,20 +1,19 @@ // @flow strict-local import type {GraphVisitor} from '@parcel/types'; +import type {ContentKey, NodeId, SerializedContentGraph} from '@parcel/graph'; import type { Asset, AssetGraphNode, AssetGroup, AssetGroupNode, AssetNode, - ContentKey, Dependency, DependencyNode, Entry, EntryFileNode, EntrySpecifierNode, Environment, - NodeId, Target, } from './types'; @@ -22,7 +21,7 @@ import invariant from 'assert'; import {hashString, Hash} from '@parcel/hash'; import {hashObject, objectSortedEntries} from '@parcel/utils'; import nullthrows from 'nullthrows'; -import ContentGraph, {type SerializedContentGraph} from './ContentGraph'; +import {ContentGraph} from '@parcel/graph'; import {createDependency} from './Dependency'; import {type ProjectPath, fromProjectPathRelative} from './projectPath'; diff --git a/packages/core/core/src/BundleGraph.js b/packages/core/core/src/BundleGraph.js index ab5a129f823..7977f0aeb5f 100644 --- a/packages/core/core/src/BundleGraph.js +++ b/packages/core/core/src/BundleGraph.js @@ -6,6 +6,7 @@ import type { Symbol, TraversalActions, } from '@parcel/types'; +import type {NodeId, SerializedContentGraph} from '@parcel/graph'; import querystring from 'querystring'; import type { @@ -16,7 +17,6 @@ import type { BundleGroup, Dependency, DependencyNode, - NodeId, InternalSourceLocation, Target, } from './types'; @@ -26,13 +26,12 @@ import type {ProjectPath} from './projectPath'; import assert from 'assert'; import invariant from 'assert'; import nullthrows from 'nullthrows'; -import {objectSortedEntriesDeep, getRootDir} from '@parcel/utils'; +import {ContentGraph, ALL_EDGE_TYPES, mapVisitor} from '@parcel/graph'; import {Hash, hashString} from '@parcel/hash'; -import {Priority, BundleBehavior} from './types'; +import {objectSortedEntriesDeep, getRootDir} from '@parcel/utils'; +import {Priority, BundleBehavior, SpecifierType} from './types'; import {getBundleGroupId, getPublicId} from './utils'; -import {ALL_EDGE_TYPES, mapVisitor} from './Graph'; -import ContentGraph, {type SerializedContentGraph} from './ContentGraph'; import {ISOLATED_ENVS} from './public/Environment'; import {fromProjectPath} from './projectPath'; @@ -770,11 +769,12 @@ export default class BundleGraph { this._graph .getNodeIdsConnectedTo(assetNodeId, bundleGraphEdgeTypes.references) .map(id => this._graph.getNode(id)) - .filter( + .some( node => node?.type === 'dependency' && - node.value.priority === Priority.lazy, - ).length > 0 + node.value.priority === Priority.lazy && + node.value.specifierType !== SpecifierType.url, + ) ) { // If this asset is referenced by any async dependency, it's referenced. return true; diff --git a/packages/core/core/src/PackagerRunner.js b/packages/core/core/src/PackagerRunner.js index 1504cb36f7d..a6d0c33d00d 100644 --- a/packages/core/core/src/PackagerRunner.js +++ b/packages/core/core/src/PackagerRunner.js @@ -215,7 +215,6 @@ export default class PackagerRunner { for (let devDep of config.devDeps) { let devDepRequest = await createDevDependency( devDep, - plugin, this.previousDevDeps, this.options, ); @@ -335,7 +334,7 @@ export default class PackagerRunner { bundle, bundleGraph: new BundleGraph( bundleGraph, - NamedBundle.get, + NamedBundle.get.bind(NamedBundle), this.options, ), getSourceMapReference: map => { @@ -378,7 +377,6 @@ export default class PackagerRunner { specifier: name, resolveFrom, }, - packager, this.previousDevDeps, this.options, ); @@ -404,7 +402,7 @@ export default class PackagerRunner { ); let bundleGraph = new BundleGraph( internalBundleGraph, - NamedBundle.get, + NamedBundle.get.bind(NamedBundle), this.options, ); let optimizers = await this.config.getOptimizers( @@ -460,7 +458,6 @@ export default class PackagerRunner { specifier: optimizer.name, resolveFrom: optimizer.resolveFrom, }, - optimizer, this.previousDevDeps, this.options, ); diff --git a/packages/core/core/src/Parcel.js b/packages/core/core/src/Parcel.js index 5032e668ce5..9aa0d713faa 100644 --- a/packages/core/core/src/Parcel.js +++ b/packages/core/core/src/Parcel.js @@ -104,9 +104,7 @@ export default class Parcel { }); } - if (resolvedOptions.cache.ensure) { - await resolvedOptions.cache.ensure(); - } + await resolvedOptions.cache.ensure(); let { dispose: disposeOptions, diff --git a/packages/core/core/src/ParcelConfig.js b/packages/core/core/src/ParcelConfig.js index f5b4021c242..6650485bcf8 100644 --- a/packages/core/core/src/ParcelConfig.js +++ b/packages/core/core/src/ParcelConfig.js @@ -8,6 +8,7 @@ import type { Runtime, PackageName, Optimizer, + Compressor, Packager, Reporter, Semver, @@ -22,6 +23,11 @@ import type { ExtendableParcelConfigPipeline, ParcelOptions, } from './types'; +import ThrowableDiagnostic, { + md, + generateJSONCodeHighlights, +} from '@parcel/diagnostic'; +import json5 from 'json5'; import {makeRe} from 'micromatch'; import {basename} from 'path'; @@ -60,6 +66,7 @@ export default class ParcelConfig { packagers: GlobMap; validators: GlobMap; optimizers: GlobMap; + compressors: GlobMap; reporters: PureParcelConfigPipeline; pluginCache: Map; regexCache: Map; @@ -74,6 +81,7 @@ export default class ParcelConfig { this.namers = config.namers || []; this.packagers = config.packagers || {}; this.optimizers = config.optimizers || {}; + this.compressors = config.compressors || {}; this.reporters = config.reporters || []; this.validators = config.validators || {}; this.pluginCache = new Map(); @@ -95,6 +103,7 @@ export default class ParcelConfig { namers: this.namers, packagers: this.packagers, optimizers: this.optimizers, + compressors: this.compressors, reporters: this.reporters, }; } @@ -150,20 +159,16 @@ export default class ParcelConfig { return Promise.all(plugins.map(p => this.loadPlugin(p))); } - _getResolverNodes(): PureParcelConfigPipeline { + async getResolvers(): Promise>> { if (this.resolvers.length === 0) { - throw new Error('No resolver plugins specified in .parcelrc config'); + throw await this.missingPluginError( + this.resolvers, + 'No resolver plugins specified in .parcelrc config', + '/resolvers', + ); } - return this.resolvers; - } - - getResolverNames(): Array { - return this._getResolverNodes().map(r => r.packageName); - } - - getResolvers(): Promise>> { - return this.loadPlugins(this._getResolverNodes()); + return this.loadPlugins(this.resolvers); } _getValidatorNodes(filePath: ProjectPath): $ReadOnlyArray { @@ -193,11 +198,11 @@ export default class ParcelConfig { .map(glob => glob.split(':')[0]); } - _getTransformerNodes( + async getTransformers( filePath: ProjectPath, pipeline?: ?string, allowEmpty?: boolean, - ): $ReadOnlyArray { + ): Promise>>> { let transformers: PureParcelConfigPipeline | null = this.matchGlobMapPipelines( filePath, this.transformers, @@ -208,58 +213,37 @@ export default class ParcelConfig { return []; } - throw new Error( - `No transformers found for ${fromProjectPathRelative(filePath)}` + + throw await this.missingPluginError( + this.transformers, + md`No transformers found for __${fromProjectPathRelative(filePath)}__` + (pipeline != null ? ` with pipeline: '${pipeline}'` : '') + '.', + '/transformers', ); } - return transformers; + return this.loadPlugins>(transformers); } - getTransformerNames( - filePath: ProjectPath, - pipeline?: ?string, - allowEmpty?: boolean, - ): Array { - let transformers = this._getTransformerNodes( - filePath, - pipeline, - allowEmpty, - ); - return transformers.map(t => t.packageName); - } - - getTransformers( - filePath: ProjectPath, - pipeline?: ?string, - allowEmpty?: boolean, - ): Promise>>> { - return this.loadPlugins>( - this._getTransformerNodes(filePath, pipeline, allowEmpty), - ); - } - - getBundlerName(): string { - if (!this.bundler) { - throw new Error('No bundler specified in .parcelrc config'); - } - - return this.bundler.packageName; - } - - getBundler(): Promise>> { + async getBundler(): Promise>> { if (!this.bundler) { - throw new Error('No bundler specified in .parcelrc config'); + throw await this.missingPluginError( + [], + 'No bundler specified in .parcelrc config', + '/bundler', + ); } return this.loadPlugin>(this.bundler); } - getNamers(): Promise>>> { + async getNamers(): Promise>>> { if (this.namers.length === 0) { - throw new Error('No namer plugins specified in .parcelrc config'); + throw await this.missingPluginError( + this.namers, + 'No namer plugins specified in .parcelrc config', + '/namers', + ); } return this.loadPlugins>(this.namers); @@ -273,23 +257,20 @@ export default class ParcelConfig { return this.loadPlugins>(this.runtimes); } - _getPackagerNode(filePath: FilePath): ParcelPluginNode { - let packagerName = this.matchGlobMap( + async getPackager( + filePath: FilePath, + ): Promise>> { + let packager = this.matchGlobMap( toProjectPathUnsafe(filePath), this.packagers, ); - if (!packagerName) { - throw new Error(`No packager found for "${filePath}".`); + if (!packager) { + throw await this.missingPluginError( + this.packagers, + md`No packager found for __${filePath}__.`, + '/packagers', + ); } - return packagerName; - } - - getPackagerName(filePath: FilePath): string { - return this._getPackagerNode(filePath).packageName; - } - - getPackager(filePath: FilePath): Promise>> { - let packager = this._getPackagerNode(filePath); return this.loadPlugin>(packager); } @@ -332,6 +313,26 @@ export default class ParcelConfig { return this.loadPlugins>(optimizers); } + async getCompressors( + filePath: FilePath, + ): Promise>> { + let compressors = + this.matchGlobMapPipelines( + toProjectPathUnsafe(filePath), + this.compressors, + ) ?? []; + + if (compressors.length === 0) { + throw await this.missingPluginError( + this.compressors, + md`No compressors found for __${filePath}__.`, + '/compressors', + ); + } + + return this.loadPlugins(compressors); + } + getReporters(): Promise>> { return this.loadPlugins(this.reporters); } @@ -424,4 +425,70 @@ export default class ParcelConfig { // $FlowFixMe afaik this should work return res; } + + async missingPluginError( + plugins: + | GlobMap + | GlobMap + | PureParcelConfigPipeline, + message: string, + key: string, + ): Promise { + let configsWithPlugin; + if (Array.isArray(plugins)) { + configsWithPlugin = new Set(getConfigPaths(this.options, plugins)); + } else { + configsWithPlugin = new Set( + Object.keys(plugins).flatMap(k => + Array.isArray(plugins[k]) + ? getConfigPaths(this.options, plugins[k]) + : [getConfigPath(this.options, plugins[k])], + ), + ); + } + + if (configsWithPlugin.size === 0) { + configsWithPlugin.add( + fromProjectPath(this.options.projectRoot, this.filePath), + ); + } + + let seenKey = false; + let codeFrames = await Promise.all( + [...configsWithPlugin].map(async filePath => { + let configContents = await this.options.inputFS.readFile( + filePath, + 'utf8', + ); + if (!json5.parse(configContents)[key.slice(1)]) { + key = ''; + } else { + seenKey = true; + } + return { + filePath, + code: configContents, + codeHighlights: generateJSONCodeHighlights(configContents, [{key}]), + }; + }), + ); + return new ThrowableDiagnostic({ + diagnostic: { + message, + origin: '@parcel/core', + codeFrames, + hints: !seenKey ? ['Try extending __@parcel/config-default__'] : [], + }, + }); + } +} + +function getConfigPaths(options, nodes) { + return nodes + .map(node => (node !== '...' ? getConfigPath(options, node) : null)) + .filter(Boolean); +} + +function getConfigPath(options, node) { + return fromProjectPath(options.projectRoot, node.resolveFrom); } diff --git a/packages/core/core/src/ParcelConfig.schema.js b/packages/core/core/src/ParcelConfig.schema.js index a54152577a2..1010154c7fb 100644 --- a/packages/core/core/src/ParcelConfig.schema.js +++ b/packages/core/core/src/ParcelConfig.schema.js @@ -121,6 +121,7 @@ export default { namers: (pipelineSchema('namer', 'namers'): SchemaEntity), packagers: (mapStringSchema('packager', 'packagers'): SchemaEntity), optimizers: (mapPipelineSchema('optimizer', 'optimizers'): SchemaEntity), + compressors: (mapPipelineSchema('compressor', 'compressors'): SchemaEntity), reporters: (pipelineSchema('reporter', 'reporters'): SchemaEntity), runtimes: (pipelineSchema('runtime', 'runtimes'): SchemaEntity), filePath: { diff --git a/packages/core/core/src/RequestTracker.js b/packages/core/core/src/RequestTracker.js index de5e8c126c0..531515385dc 100644 --- a/packages/core/core/src/RequestTracker.js +++ b/packages/core/core/src/RequestTracker.js @@ -4,9 +4,8 @@ import type {AbortSignal} from 'abortcontroller-polyfill/dist/cjs-ponyfill'; import type {Async, EnvMap} from '@parcel/types'; import type {EventType, Options as WatcherOptions} from '@parcel/watcher'; import type WorkerFarm from '@parcel/workers'; +import type {ContentKey, NodeId, SerializedContentGraph} from '@parcel/graph'; import type { - ContentKey, - NodeId, ParcelOptions, RequestInvalidation, InternalFile, @@ -24,7 +23,7 @@ import { makeDeferredWithPromise, } from '@parcel/utils'; import {hashString} from '@parcel/hash'; -import ContentGraph, {type SerializedContentGraph} from './ContentGraph'; +import {ContentGraph} from '@parcel/graph'; import {assertSignalNotAborted, hashFromOption} from './utils'; import { type ProjectPath, diff --git a/packages/core/core/src/Transformation.js b/packages/core/core/src/Transformation.js index c8d31ee3186..4511843dc92 100644 --- a/packages/core/core/src/Transformation.js +++ b/packages/core/core/src/Transformation.js @@ -95,6 +95,7 @@ export default class Transformation { request: TransformationRequest; configs: Map; devDepRequests: Map; + pluginDevDeps: Array; options: ParcelOptions; pluginOptions: PluginOptions; workerApi: WorkerApi; @@ -111,16 +112,23 @@ export default class Transformation { this.invalidations = new Map(); this.invalidateOnFileCreate = []; this.devDepRequests = new Map(); + this.pluginDevDeps = []; this.pluginOptions = new PluginOptions( - optionsProxy(this.options, option => { - let invalidation: RequestInvalidation = { - type: 'option', - key: option, - }; + optionsProxy( + this.options, + option => { + let invalidation: RequestInvalidation = { + type: 'option', + key: option, + }; - this.invalidations.set(getInvalidationId(invalidation), invalidation); - }), + this.invalidations.set(getInvalidationId(invalidation), invalidation); + }, + devDep => { + this.pluginDevDeps.push(devDep); + }, + ), ); } @@ -261,14 +269,17 @@ export default class Transformation { // Add dev dep requests for each transformer for (let transformer of pipeline.transformers) { - await this.addDevDependency( - { - specifier: transformer.name, - resolveFrom: transformer.resolveFrom, - range: transformer.range, - }, - transformer, - ); + await this.addDevDependency({ + specifier: transformer.name, + resolveFrom: transformer.resolveFrom, + range: transformer.range, + }); + } + + // Add dev dep requests for dependencies of transformer plugins + // (via proxied packageManager.require calls). + for (let devDep of this.pluginDevDeps) { + await this.addDevDependency(devDep); } if (!initialCacheEntry) { @@ -340,12 +351,7 @@ export default class Transformation { return hashString(hashes); } - async addDevDependency( - opts: InternalDevDepOptions, - transformer: - | LoadedPlugin> - | TransformerWithNameAndConfig, - ): Promise { + async addDevDependency(opts: InternalDevDepOptions): Promise { let {specifier, resolveFrom, range} = opts; let key = `${specifier}:${fromProjectPathRelative(resolveFrom)}`; if (this.devDepRequests.has(key)) { @@ -363,7 +369,6 @@ export default class Transformation { let devDepRequest = await createDevDependency( opts, - transformer, this.request.devDeps, this.options, ); @@ -663,7 +668,7 @@ export default class Transformation { await loadPluginConfig(transformer, config, this.options); for (let devDep of config.devDeps) { - await this.addDevDependency(devDep, transformer); + await this.addDevDependency(devDep); } return config; diff --git a/packages/core/core/src/applyRuntimes.js b/packages/core/core/src/applyRuntimes.js index f16a65b17b9..fcd2a9a6707 100644 --- a/packages/core/core/src/applyRuntimes.js +++ b/packages/core/core/src/applyRuntimes.js @@ -1,11 +1,11 @@ // @flow strict-local +import type {ContentKey} from '@parcel/graph'; import type {Dependency, NamedBundle as INamedBundle} from '@parcel/types'; import type {SharedReference} from '@parcel/workers'; import type { AssetGroup, Bundle as InternalBundle, - ContentKey, Config, DevDepRequest, ParcelOptions, @@ -69,7 +69,7 @@ export default async function applyRuntimes({ bundle: NamedBundle.get(bundle, bundleGraph, options), bundleGraph: new BundleGraph( bundleGraph, - NamedBundle.get, + NamedBundle.get.bind(NamedBundle), options, ), config: configs.get(runtime.name)?.result, @@ -125,7 +125,6 @@ export default async function applyRuntimes({ specifier: runtime.name, resolveFrom: runtime.resolveFrom, }, - runtime, previousDevDeps, options, ); diff --git a/packages/core/core/src/dumpGraphToGraphViz.js b/packages/core/core/src/dumpGraphToGraphViz.js index 3c649816855..1441e5ca3e3 100644 --- a/packages/core/core/src/dumpGraphToGraphViz.js +++ b/packages/core/core/src/dumpGraphToGraphViz.js @@ -1,11 +1,11 @@ // @flow +import type {Graph} from '@parcel/graph'; import type {AssetGraphNode, BundleGraphNode, Environment} from './types'; -import type Graph from './Graph'; -import {SpecifierType, Priority} from './types'; import path from 'path'; import {fromProjectPathRelative} from './projectPath'; +import {SpecifierType, Priority} from './types'; const COLORS = { root: 'gray', diff --git a/packages/core/core/src/index.js b/packages/core/core/src/index.js index c46ac20d832..70e42eb2663 100644 --- a/packages/core/core/src/index.js +++ b/packages/core/core/src/index.js @@ -12,6 +12,7 @@ export { export { default, + default as Parcel, BuildError, createWorkerFarm, INTERNAL_RESOLVE, diff --git a/packages/core/core/src/public/Bundle.js b/packages/core/core/src/public/Bundle.js index c7a5f539e5f..00793ad4c66 100644 --- a/packages/core/core/src/public/Bundle.js +++ b/packages/core/core/src/public/Bundle.js @@ -25,7 +25,7 @@ import nullthrows from 'nullthrows'; import {DefaultWeakMap} from '@parcel/utils'; import {assetToAssetValue, assetFromValue} from './Asset'; -import {mapVisitor} from '../Graph'; +import {mapVisitor} from '@parcel/graph'; import Environment from './Environment'; import Dependency, {dependencyToInternalDependency} from './Dependency'; import Target from './Target'; diff --git a/packages/core/core/src/public/BundleGraph.js b/packages/core/core/src/public/BundleGraph.js index 3567cc38e19..b94b5d34dcc 100644 --- a/packages/core/core/src/public/BundleGraph.js +++ b/packages/core/core/src/public/BundleGraph.js @@ -20,11 +20,11 @@ import type InternalBundleGraph from '../BundleGraph'; import invariant from 'assert'; import nullthrows from 'nullthrows'; +import {mapVisitor} from '@parcel/graph'; import {assetFromValue, assetToAssetValue, Asset} from './Asset'; import {bundleToInternalBundle} from './Bundle'; import Dependency, {dependencyToInternalDependency} from './Dependency'; import {targetToInternalTarget} from './Target'; -import {mapVisitor} from '../Graph'; import {fromInternalSourceLocation} from '../utils'; import BundleGroup, {bundleGroupToInternalBundleGroup} from './BundleGroup'; @@ -50,10 +50,6 @@ export default class BundleGraph implements IBundleGraph { #graph: InternalBundleGraph; #options: ParcelOptions; - // This is invoked as `this.#createBundle.call(null, ...)` below, as private - // properties aren't currently callable in Flow: - // https://github.com/parcel-bundler/parcel/pull/4591#discussion_r422661115 - // https://github.com/facebook/flow/issues/7877 #createBundle: BundleFactory; constructor( @@ -117,9 +113,7 @@ export default class BundleGraph ): Array { return this.#graph .getReferencedBundles(bundleToInternalBundle(bundle), opts) - .map(bundle => - this.#createBundle.call(null, bundle, this.#graph, this.#options), - ); + .map(bundle => this.#createBundle(bundle, this.#graph, this.#options)); } resolveAsyncDependency( @@ -156,7 +150,7 @@ export default class BundleGraph ); if (result != null) { - return this.#createBundle.call(null, result, this.#graph, this.#options); + return this.#createBundle(result, this.#graph, this.#options); } } @@ -196,17 +190,13 @@ export default class BundleGraph bundleGroupToInternalBundleGroup(bundleGroup), opts, ) - .map(bundle => - this.#createBundle.call(null, bundle, this.#graph, this.#options), - ); + .map(bundle => this.#createBundle(bundle, this.#graph, this.#options)); } getBundles(opts?: {|includeInline: boolean|}): Array { return this.#graph .getBundles(opts) - .map(bundle => - this.#createBundle.call(null, bundle, this.#graph, this.#options), - ); + .map(bundle => this.#createBundle(bundle, this.#graph, this.#options)); } isEntryBundleGroup(bundleGroup: IBundleGroup): boolean { @@ -218,17 +208,13 @@ export default class BundleGraph getChildBundles(bundle: IBundle): Array { return this.#graph .getChildBundles(bundleToInternalBundle(bundle)) - .map(bundle => - this.#createBundle.call(null, bundle, this.#graph, this.#options), - ); + .map(bundle => this.#createBundle(bundle, this.#graph, this.#options)); } getParentBundles(bundle: IBundle): Array { return this.#graph .getParentBundles(bundleToInternalBundle(bundle)) - .map(bundle => - this.#createBundle.call(null, bundle, this.#graph, this.#options), - ); + .map(bundle => this.#createBundle(bundle, this.#graph, this.#options)); } getSymbolResolution( @@ -289,8 +275,7 @@ export default class BundleGraph ): ?TContext { return this.#graph.traverseBundles( mapVisitor( - bundle => - this.#createBundle.call(null, bundle, this.#graph, this.#options), + bundle => this.#createBundle(bundle, this.#graph, this.#options), visit, ), startBundle == null ? undefined : bundleToInternalBundle(startBundle), @@ -300,17 +285,13 @@ export default class BundleGraph getBundlesWithAsset(asset: IAsset): Array { return this.#graph .getBundlesWithAsset(assetToAssetValue(asset)) - .map(bundle => - this.#createBundle.call(null, bundle, this.#graph, this.#options), - ); + .map(bundle => this.#createBundle(bundle, this.#graph, this.#options)); } getBundlesWithDependency(dependency: IDependency): Array { return this.#graph .getBundlesWithDependency(dependencyToInternalDependency(dependency)) - .map(bundle => - this.#createBundle.call(null, bundle, this.#graph, this.#options), - ); + .map(bundle => this.#createBundle(bundle, this.#graph, this.#options)); } getUsedSymbols(v: IAsset | IDependency): $ReadOnlySet { diff --git a/packages/core/core/src/public/MutableBundleGraph.js b/packages/core/core/src/public/MutableBundleGraph.js index 1c977ca16d5..e59a2d8ac9c 100644 --- a/packages/core/core/src/public/MutableBundleGraph.js +++ b/packages/core/core/src/public/MutableBundleGraph.js @@ -34,7 +34,7 @@ export default class MutableBundleGraph extends BundleGraph #bundlePublicIds /*: Set */ = new Set(); constructor(graph: InternalBundleGraph, options: ParcelOptions) { - super(graph, Bundle.get, options); + super(graph, Bundle.get.bind(Bundle), options); this.#graph = graph; this.#options = options; } diff --git a/packages/core/core/src/requests/AssetGraphRequest.js b/packages/core/core/src/requests/AssetGraphRequest.js index 82b17ce4a2f..89969dff840 100644 --- a/packages/core/core/src/requests/AssetGraphRequest.js +++ b/packages/core/core/src/requests/AssetGraphRequest.js @@ -1,8 +1,9 @@ // @flow strict-local +import type {Diagnostic} from '@parcel/diagnostic'; +import type {NodeId} from '@parcel/graph'; import type {Async, Symbol, Meta} from '@parcel/types'; import type {SharedReference} from '@parcel/workers'; -import type {Diagnostic} from '@parcel/diagnostic'; import type { Asset, AssetGroup, @@ -12,7 +13,6 @@ import type { DependencyNode, Entry, InternalSourceLocation, - NodeId, ParcelOptions, Target, } from '../types'; @@ -25,7 +25,7 @@ import nullthrows from 'nullthrows'; import {PromiseQueue} from '@parcel/utils'; import {hashString} from '@parcel/hash'; import ThrowableDiagnostic, {md} from '@parcel/diagnostic'; -import {Priority} from '../types'; +import {BundleBehavior, Priority} from '../types'; import AssetGraph from '../AssetGraph'; import {PARCEL_VERSION} from '../constants'; import createEntryRequest from './EntryRequest'; @@ -471,6 +471,8 @@ export class AssetGraphBuilder { for (let s of incomingDep.usedSymbolsDown) { if ( assetSymbols == null || // Assume everything could be provided if symbols are cleared + assetNode.value.bundleBehavior === BundleBehavior.isolated || + assetNode.value.bundleBehavior === BundleBehavior.inline || assetNode.usedSymbols.has(s) || reexportedSymbols.has(s) || s === '*' diff --git a/packages/core/core/src/requests/AssetRequest.js b/packages/core/core/src/requests/AssetRequest.js index 76d2323c6dc..65293c785f1 100644 --- a/packages/core/core/src/requests/AssetRequest.js +++ b/packages/core/core/src/requests/AssetRequest.js @@ -1,11 +1,11 @@ // @flow strict-local +import type {ContentKey} from '@parcel/graph'; import type {Async} from '@parcel/types'; import type {StaticRunOpts} from '../RequestTracker'; import type { AssetRequestInput, AssetRequestResult, - ContentKey, DevDepRequest, TransformationRequest, } from '../types'; diff --git a/packages/core/core/src/requests/BundleGraphRequest.js b/packages/core/core/src/requests/BundleGraphRequest.js index a3a2a8295f7..13da2f1dbac 100644 --- a/packages/core/core/src/requests/BundleGraphRequest.js +++ b/packages/core/core/src/requests/BundleGraphRequest.js @@ -148,7 +148,6 @@ class BundlerRunner { for (let devDep of config.devDeps) { let devDepRequest = await createDevDependency( devDep, - plugin, this.previousDevDeps, this.options, ); @@ -212,7 +211,7 @@ class BundlerRunner { this.options, ); - let logger = new PluginLogger({origin: this.config.getBundlerName()}); + let logger = new PluginLogger({origin: name}); try { await bundler.bundle({ @@ -224,7 +223,7 @@ class BundlerRunner { } catch (e) { throw new ThrowableDiagnostic({ diagnostic: errorToDiagnostic(e, { - origin: this.config.getBundlerName(), + origin: name, }), }); } finally { @@ -247,7 +246,7 @@ class BundlerRunner { } catch (e) { throw new ThrowableDiagnostic({ diagnostic: errorToDiagnostic(e, { - origin: this.config.getBundlerName(), + origin: name, }), }); } finally { @@ -267,7 +266,6 @@ class BundlerRunner { specifier: name, resolveFrom, }, - plugin, this.previousDevDeps, this.options, ); @@ -345,7 +343,6 @@ class BundlerRunner { specifier: namer.name, resolveFrom: namer.resolveFrom, }, - namer, this.previousDevDeps, this.options, ); @@ -370,7 +367,7 @@ class BundlerRunner { let bundle = Bundle.get(internalBundle, internalBundleGraph, this.options); let bundleGraph = new BundleGraph( internalBundleGraph, - NamedBundle.get, + NamedBundle.get.bind(NamedBundle), this.options, ); diff --git a/packages/core/core/src/requests/DevDepRequest.js b/packages/core/core/src/requests/DevDepRequest.js index cd1e63b306f..adcda409048 100644 --- a/packages/core/core/src/requests/DevDepRequest.js +++ b/packages/core/core/src/requests/DevDepRequest.js @@ -27,7 +27,6 @@ const devDepRequestCache = new WeakMap(); export async function createDevDependency( opts: InternalDevDepOptions, - plugin: {name: DependencySpecifier, resolveFrom: ProjectPath, ...}, requestDevDeps: Map, options: ParcelOptions, ): Promise { diff --git a/packages/core/core/src/requests/PackageRequest.js b/packages/core/core/src/requests/PackageRequest.js index 1f5c34f485b..8356b1fed56 100644 --- a/packages/core/core/src/requests/PackageRequest.js +++ b/packages/core/core/src/requests/PackageRequest.js @@ -1,9 +1,11 @@ // @flow strict-local +import type {ContentKey} from '@parcel/graph'; import type {Async} from '@parcel/types'; import type {SharedReference} from '@parcel/workers'; + import type {StaticRunOpts} from '../RequestTracker'; -import type {Bundle, ContentKey} from '../types'; +import type {Bundle} from '../types'; import type BundleGraph from '../BundleGraph'; import type {BundleInfo} from '../PackagerRunner'; import type {ConfigAndCachePath} from './ParcelConfigRequest'; diff --git a/packages/core/core/src/requests/ParcelBuildRequest.js b/packages/core/core/src/requests/ParcelBuildRequest.js index eeb5e5c63ea..56b690afe78 100644 --- a/packages/core/core/src/requests/ParcelBuildRequest.js +++ b/packages/core/core/src/requests/ParcelBuildRequest.js @@ -1,11 +1,13 @@ // @flow strict-local +import type {ContentKey} from '@parcel/graph'; import type {Async} from '@parcel/types'; import type {SharedReference} from '@parcel/workers'; +import type {AbortSignal} from 'abortcontroller-polyfill/dist/cjs-ponyfill'; + import type {StaticRunOpts} from '../RequestTracker'; -import type {Asset, AssetGroup, ContentKey, PackagedBundleInfo} from '../types'; +import type {Asset, AssetGroup, PackagedBundleInfo} from '../types'; import type BundleGraph from '../BundleGraph'; -import type {AbortSignal} from 'abortcontroller-polyfill/dist/cjs-ponyfill'; import createAssetGraphRequest from './AssetGraphRequest'; import createBundleGraphRequest from './BundleGraphRequest'; diff --git a/packages/core/core/src/requests/ParcelConfigRequest.js b/packages/core/core/src/requests/ParcelConfigRequest.js index b2562c93855..ed9b9409f61 100644 --- a/packages/core/core/src/requests/ParcelConfigRequest.js +++ b/packages/core/core/src/requests/ParcelConfigRequest.js @@ -264,6 +264,16 @@ function processPipeline( } } +const RESERVED_PIPELINES = new Set([ + 'node:', + 'npm:', + 'http:', + 'https:', + 'data:', + 'tel:', + 'mailto:', +]); + async function processMap( // $FlowFixMe map: ?ConfigMap, @@ -277,12 +287,12 @@ async function processMap( // $FlowFixMe let res: ConfigMap = {}; for (let k in map) { - if (k.startsWith('node:')) { + let i = k.indexOf(':'); + if (i > 0 && RESERVED_PIPELINES.has(k.slice(0, i + 1))) { let code = await options.inputFS.readFile(filePath, 'utf8'); throw new ThrowableDiagnostic({ diagnostic: { - message: - 'Named pipeline `node:` is reserved for builtin Node.js libraries', + message: `Named pipeline '${k.slice(0, i + 1)}' is reserved.`, origin: '@parcel/core', codeFrames: [ { @@ -297,6 +307,8 @@ async function processMap( ]), }, ], + documentationURL: + 'https://v2.parceljs.org/features/dependency-resolution/#url-schemes', }, }); } @@ -376,6 +388,12 @@ export async function processConfig( configFile.filePath, options, ), + compressors: await processMap( + configFile.compressors, + '/compressors', + configFile.filePath, + options, + ), reporters: processPipeline( options, configFile.reporters, @@ -598,6 +616,7 @@ export function mergeConfigs( runtimes: assertPurePipeline(mergePipelines(base.runtimes, ext.runtimes)), packagers: mergeMaps(base.packagers, ext.packagers), optimizers: mergeMaps(base.optimizers, ext.optimizers, mergePipelines), + compressors: mergeMaps(base.compressors, ext.compressors, mergePipelines), reporters: assertPurePipeline( mergePipelines(base.reporters, ext.reporters), ), diff --git a/packages/core/core/src/requests/PathRequest.js b/packages/core/core/src/requests/PathRequest.js index ada5fb8dddf..73bdcd62c93 100644 --- a/packages/core/core/src/requests/PathRequest.js +++ b/packages/core/core/src/requests/PathRequest.js @@ -1,11 +1,6 @@ // @flow strict-local import type {Diagnostic} from '@parcel/diagnostic'; -import type { - Async, - FileCreateInvalidation, - FilePath, - QueryParameters, -} from '@parcel/types'; +import type {Async, FileCreateInvalidation, FilePath} from '@parcel/types'; import type {StaticRunOpts} from '../RequestTracker'; import type {AssetGroup, Dependency, ParcelOptions} from '../types'; import type {ConfigAndCachePath} from './ParcelConfigRequest'; @@ -14,9 +9,7 @@ import ThrowableDiagnostic, {errorToDiagnostic, md} from '@parcel/diagnostic'; import {PluginLogger} from '@parcel/logger'; import nullthrows from 'nullthrows'; import path from 'path'; -import URL from 'url'; import {normalizePath} from '@parcel/utils'; -import querystring from 'querystring'; import {report} from '../ReporterRunner'; import PublicDependency from '../public/Dependency'; import PluginOptions from '../public/PluginOptions'; @@ -50,7 +43,6 @@ type RunOpts = {| |}; const type = 'path_request'; -const QUERY_PARAMS_REGEX = /^([^\t\r\n\v\f?]*)(\?.*)?/; const PIPELINE_REGEX = /^([a-z0-9-]+?):(.*)$/i; export default function createPathRequest( @@ -166,8 +158,7 @@ export class ResolverRunner { let resolvers = await this.config.getResolvers(); let pipeline; - let filePath; - let query: ?QueryParameters; + let specifier; let validPipelines = new Set(this.config.getNamedPipelines()); let match = dependency.specifier.match(PIPELINE_REGEX); if ( @@ -176,74 +167,20 @@ export class ResolverRunner { // and include e.g. `C:\` on Windows, conflicting with pipelines. !path.isAbsolute(dependency.specifier) ) { - if (dependency.specifier.startsWith('node:')) { - filePath = dependency.specifier; - } else { - [, pipeline, filePath] = match; - if (!validPipelines.has(pipeline)) { - if (dep.specifierType === 'url') { - // This may be a url protocol or scheme rather than a pipeline, such as - // `url('http://example.com/foo.png')` - return {assetGroup: null}; - } else { - return { - assetGroup: null, - diagnostics: [ - await this.getDiagnostic( - dependency, - md`Unknown pipeline: ${pipeline}.`, - ), - ], - }; - } - } - } - } else { - if (dep.specifierType === 'url') { - if (dependency.specifier.startsWith('//')) { - // A protocol-relative URL, e.g `url('//example.com/foo.png')` - return {assetGroup: null}; - } - if (dependency.specifier.startsWith('#')) { - // An ID-only URL, e.g. `url(#clip-path)` for CSS rules - return {assetGroup: null}; - } - } - filePath = dependency.specifier; - } - - let queryPart = null; - if (dep.specifierType === 'url') { - let parsed = URL.parse(filePath); - if (typeof parsed.pathname !== 'string') { - return { - assetGroup: null, - diagnostics: [ - await this.getDiagnostic( - dependency, - md`Received URL without a pathname ${filePath}.`, - ), - ], - }; - } - filePath = decodeURIComponent(parsed.pathname); - if (parsed.query != null) { - queryPart = parsed.query; + [, pipeline, specifier] = match; + if (!validPipelines.has(pipeline)) { + // This may be a url protocol or scheme rather than a pipeline, such as + // `url('http://example.com/foo.png')`. Pass it to resolvers to handle. + specifier = dependency.specifier; + pipeline = null; } } else { - let matchesQuerystring = filePath.match(QUERY_PARAMS_REGEX); - if (matchesQuerystring && matchesQuerystring[2] != null) { - filePath = matchesQuerystring[1]; - queryPart = matchesQuerystring[2].substr(1); - } - } - if (queryPart != null) { - query = querystring.parse(queryPart); + specifier = dependency.specifier; } // Entrypoints, convert ProjectPath in module specifier to absolute path if (dep.resolveFrom == null) { - filePath = path.join(this.options.projectRoot, filePath); + specifier = path.join(this.options.projectRoot, specifier); } let diagnostics: Array = []; let invalidateOnFileCreate = []; @@ -251,7 +188,7 @@ export class ResolverRunner { for (let resolver of resolvers) { try { let result = await resolver.plugin.resolve({ - filePath, + specifier, pipeline, dependency: dep, options: this.pluginOptions, @@ -302,7 +239,7 @@ export class ResolverRunner { this.options.projectRoot, resultFilePath, ), - query, + query: result.query, sideEffects: result.sideEffects, code: result.code, env: dependency.env, @@ -322,7 +259,7 @@ export class ResolverRunner { new ThrowableDiagnostic({diagnostic: result.diagnostics}), { origin: resolver.name, - filePath, + filePath: specifier, }, ); diagnostics.push(...errorDiagnostic); @@ -332,7 +269,7 @@ export class ResolverRunner { // Add error to error map, we'll append these to the standard error if we can't resolve the asset let errorDiagnostic = errorToDiagnostic(e, { origin: resolver.name, - filePath, + filePath: specifier, }); if (Array.isArray(errorDiagnostic)) { diagnostics.push(...errorDiagnostic); diff --git a/packages/core/core/src/requests/TargetRequest.js b/packages/core/core/src/requests/TargetRequest.js index 3e28ba3e7d4..03d95e267ad 100644 --- a/packages/core/core/src/requests/TargetRequest.js +++ b/packages/core/core/src/requests/TargetRequest.js @@ -592,6 +592,8 @@ export class TargetResolver { hints: [ `The "${targetName}" field is meant for libraries. If you meant to output a ${ext} file, either remove the "${targetName}" field or choose a different target name.`, ], + documentationURL: + 'https://v2.parceljs.org/features/targets/#library-targets', }, }); } @@ -622,6 +624,8 @@ export class TargetResolver { hints: [ `The "${targetName}" field is meant for libraries. The outputFormat must be either "commonjs" or "esmodule". Either change or remove the declared outputFormat.`, ], + documentationURL: + 'https://v2.parceljs.org/features/targets/#library-targets', }, }); } @@ -679,6 +683,8 @@ export class TargetResolver { hints: [ `Either change the output file extension to .mjs, add "type": "module" to package.json, or remove the declared outputFormat.`, ], + documentationURL: + 'https://v2.parceljs.org/features/targets/#library-targets', }, }); } @@ -709,6 +715,8 @@ export class TargetResolver { hints: [ `The "${targetName}" target is meant for libraries. Either remove the "scopeHoist" option, or use a different target name.`, ], + documentationURL: + 'https://v2.parceljs.org/features/targets/#library-targets', }, }); } @@ -850,6 +858,8 @@ export class TargetResolver { }, ], hints: [`Either remove the "scopeHoist" or "isLibrary" option.`], + documentationURL: + 'https://v2.parceljs.org/features/targets/#library-targets', }, }); } @@ -1016,6 +1026,8 @@ export class TargetResolver { expectedExtensions, )}.`, ], + documentationURL: + 'https://v2.parceljs.org/features/targets/#library-targets', }, }); } @@ -1239,8 +1251,9 @@ function assertTargetsAreNotEntries( (COMMON_TARGETS[target.name] ? `The "${target.name}" field is an _output_ file path so that your build can be consumed by other tools. ` : '') + - `Change the "${target.name}" field to point to an output file rather than your source code. See https://v2.parceljs.org/configuration/package-json for more information.`, + `Change the "${target.name}" field to point to an output file rather than your source code.`, ], + documentationURL: 'https://v2.parceljs.org/features/targets/', }, }); } diff --git a/packages/core/core/src/requests/WriteBundleRequest.js b/packages/core/core/src/requests/WriteBundleRequest.js index 634a81b7938..80a997b41b7 100644 --- a/packages/core/core/src/requests/WriteBundleRequest.js +++ b/packages/core/core/src/requests/WriteBundleRequest.js @@ -1,19 +1,43 @@ // @flow strict-local -import type {Async, FilePath} from '@parcel/types'; -import type {StaticRunOpts} from '../RequestTracker'; -import type {Bundle, ContentKey, PackagedBundleInfo} from '../types'; import type {FileSystem, FileOptions} from '@parcel/fs'; +import type {ContentKey} from '@parcel/graph'; +import type {Async, FilePath, Compressor} from '@parcel/types'; + +import type {RunAPI, StaticRunOpts} from '../RequestTracker'; +import type {Bundle, PackagedBundleInfo, ParcelOptions} from '../types'; import type BundleGraph from '../BundleGraph'; import type {BundleInfo} from '../PackagerRunner'; +import type {ConfigAndCachePath} from './ParcelConfigRequest'; +import type {LoadedPlugin} from '../ParcelConfig'; +import type {ProjectPath} from '../projectPath'; import {HASH_REF_PREFIX, HASH_REF_REGEX} from '../constants'; import nullthrows from 'nullthrows'; import path from 'path'; import {NamedBundle} from '../public/Bundle'; import {TapStream} from '@parcel/utils'; -import {Readable, Transform} from 'stream'; -import {fromProjectPath, toProjectPath, joinProjectPath} from '../projectPath'; +import {Readable, Transform, pipeline} from 'stream'; +import { + fromProjectPath, + fromProjectPathRelative, + toProjectPath, + joinProjectPath, + toProjectPathUnsafe, +} from '../projectPath'; +import createParcelConfigRequest, { + getCachedParcelConfig, +} from './ParcelConfigRequest'; +import PluginOptions from '../public/PluginOptions'; +import {PluginLogger} from '@parcel/logger'; +import { + getDevDepRequests, + invalidateDevDeps, + createDevDependency, + runDevDepRequest, +} from './DevDepRequest'; +import ParcelConfig from '../ParcelConfig'; +import ThrowableDiagnostic, {errorToDiagnostic} from '@parcel/diagnostic'; const BOUNDARY_LENGTH = HASH_REF_PREFIX.length + 32 - 1; @@ -100,13 +124,32 @@ async function run({input, options, api}: RunInput) { mode: (await inputFS.stat(mainEntry.filePath)).mode, }; let contentStream = options.cache.getStream(cacheKeys.content); - let size = await writeFileStream( - outputFS, - fullPath, + let size = 0; + contentStream = contentStream.pipe( + new TapStream(buf => { + size += buf.length; + }), + ); + + let configResult = nullthrows( + await api.runRequest(createParcelConfigRequest()), + ); + let config = getCachedParcelConfig(configResult, options); + + let {devDeps, invalidDevDeps} = await getDevDepRequests(api); + invalidateDevDeps(invalidDevDeps, options, config); + + await writeFiles( contentStream, - info.hashReferences, + info, hashRefToNameHash, + options, + config, + outputFS, + filePath, writeOptions, + devDeps, + api, ); if ( @@ -115,13 +158,17 @@ async function run({input, options, api}: RunInput) { !bundle.env.sourceMap.inline && (await options.cache.has(mapKey)) ) { - let mapStream = options.cache.getStream(mapKey); - await writeFileStream( - outputFS, - fullPath + '.map', - mapStream, - info.hashReferences, + await writeFiles( + options.cache.getStream(mapKey), + info, hashRefToNameHash, + options, + config, + outputFS, + toProjectPathUnsafe(fromProjectPathRelative(filePath) + '.map'), + writeOptions, + devDeps, + api, ); } @@ -137,33 +184,94 @@ async function run({input, options, api}: RunInput) { return res; } -function writeFileStream( - fs: FileSystem, - filePath: FilePath, - stream: Readable, - hashReferences: Array, +async function writeFiles( + inputStream: stream$Readable, + info: BundleInfo, hashRefToNameHash: Map, - options: ?FileOptions, -): Promise { - return new Promise((resolve, reject) => { - let initialStream = hashReferences.length - ? stream.pipe(replaceStream(hashRefToNameHash)) - : stream; - let fsStream = fs.createWriteStream(filePath, options); - let fsStreamClosed = new Promise(resolve => { - fsStream.on('close', () => resolve()); + options: ParcelOptions, + config: ParcelConfig, + outputFS: FileSystem, + filePath: ProjectPath, + writeOptions: ?FileOptions, + devDeps: Map, + api: RunAPI, +) { + let compressors = await config.getCompressors( + fromProjectPathRelative(filePath), + ); + let fullPath = fromProjectPath(options.projectRoot, filePath); + + let stream = info.hashReferences.length + ? inputStream.pipe(replaceStream(hashRefToNameHash)) + : inputStream; + + let promises = []; + for (let compressor of compressors) { + promises.push( + runCompressor( + compressor, + cloneStream(stream), + options, + outputFS, + fullPath, + writeOptions, + devDeps, + api, + ), + ); + } + + await Promise.all(promises); +} + +async function runCompressor( + compressor: LoadedPlugin, + stream: stream$Readable, + options: ParcelOptions, + outputFS: FileSystem, + filePath: FilePath, + writeOptions: ?FileOptions, + devDeps: Map, + api: RunAPI, +) { + try { + let res = await compressor.plugin.compress({ + stream, + options: new PluginOptions(options), + logger: new PluginLogger({origin: compressor.name}), }); - let bytesWritten = 0; - initialStream - .pipe( - new TapStream(buf => { - bytesWritten += buf.length; - }), - ) - .pipe(fsStream) - .on('finish', () => resolve(fsStreamClosed.then(() => bytesWritten))) - .on('error', reject); - }); + + await new Promise((resolve, reject) => + pipeline( + res.stream, + outputFS.createWriteStream( + filePath + (res.type != null ? '.' + res.type : ''), + writeOptions, + ), + err => { + if (err) reject(err); + else resolve(); + }, + ), + ); + } catch (err) { + throw new ThrowableDiagnostic({ + diagnostic: errorToDiagnostic(err, { + origin: compressor.name, + }), + }); + } finally { + // Add dev deps for compressor plugins AFTER running them, to account for lazy require(). + let devDepRequest = await createDevDependency( + { + specifier: compressor.name, + resolveFrom: compressor.resolveFrom, + }, + devDeps, + options, + ); + await runDevDepRequest(api, devDepRequest); + } } function replaceStream(hashRefToNameHash) { @@ -187,3 +295,13 @@ function replaceStream(hashRefToNameHash) { }, }); } + +function cloneStream(readable) { + let res = new Readable(); + // $FlowFixMe + res._read = () => {}; + readable.on('data', chunk => res.push(chunk)); + readable.on('end', () => res.push(null)); + readable.on('error', err => res.emit('error', err)); + return res; +} diff --git a/packages/core/core/src/requests/WriteBundlesRequest.js b/packages/core/core/src/requests/WriteBundlesRequest.js index 176be6408c2..e33974e8b93 100644 --- a/packages/core/core/src/requests/WriteBundlesRequest.js +++ b/packages/core/core/src/requests/WriteBundlesRequest.js @@ -1,9 +1,10 @@ // @flow strict-local +import type {ContentKey} from '@parcel/graph'; import type {Async} from '@parcel/types'; import type {SharedReference} from '@parcel/workers'; import type {StaticRunOpts} from '../RequestTracker'; -import type {ContentKey, PackagedBundleInfo} from '../types'; +import type {PackagedBundleInfo} from '../types'; import type BundleGraph from '../BundleGraph'; import type {BundleInfo} from '../PackagerRunner'; diff --git a/packages/core/core/src/resolveOptions.js b/packages/core/core/src/resolveOptions.js index 2f35ad7e84a..b0992beba1d 100644 --- a/packages/core/core/src/resolveOptions.js +++ b/packages/core/core/src/resolveOptions.js @@ -106,8 +106,7 @@ export default async function resolveOptions( projectRoot, initialOptions.defaultConfig, ), - shouldPatchConsole: - initialOptions.shouldPatchConsole ?? process.env.NODE_ENV !== 'test', + shouldPatchConsole: initialOptions.shouldPatchConsole ?? false, env: { ...process.env, ...initialOptions.env, diff --git a/packages/core/core/src/types.js b/packages/core/core/src/types.js index 177a200a9d8..565b43bc67a 100644 --- a/packages/core/core/src/types.js +++ b/packages/core/core/src/types.js @@ -1,5 +1,6 @@ // @flow strict-local +import type {ContentKey} from '@parcel/graph'; import type { ASTGenerator, BuildMode, @@ -51,6 +52,7 @@ export type ProcessedParcelConfig = {| runtimes?: PureParcelConfigPipeline, packagers?: {[Glob]: ParcelPluginNode, ...}, optimizers?: {[Glob]: ExtendableParcelConfigPipeline, ...}, + compressors?: {[Glob]: ExtendableParcelConfigPipeline, ...}, reporters?: PureParcelConfigPipeline, validators?: {[Glob]: ExtendableParcelConfigPipeline, ...}, filePath: ProjectPath, @@ -284,23 +286,6 @@ export type ParcelOptions = {| |}, |}; -// forcing NodeId to be opaque as it should only be created once -export opaque type NodeId = number; -export function toNodeId(x: number): NodeId { - return x; -} -export function fromNodeId(x: NodeId): number { - return x; -} - -export type ContentKey = string; - -export type Edge = {| - from: NodeId, - to: NodeId, - type: TEdgeType, -|}; - export type AssetNode = {| id: ContentKey, +type: 'asset', diff --git a/packages/core/core/src/utils.js b/packages/core/core/src/utils.js index ca7de3b00ff..ecd5b479a83 100644 --- a/packages/core/core/src/utils.js +++ b/packages/core/core/src/utils.js @@ -11,15 +11,18 @@ import type { ParcelOptions, InternalFileCreateInvalidation, InternalSourceLocation, + InternalDevDepOptions, } from './types'; +import type {PackageManager} from '@parcel/package-manager'; import invariant from 'assert'; import baseX from 'base-x'; +import {Graph} from '@parcel/graph'; import {hashObject} from '@parcel/utils'; + import {registerSerializableClass} from './serializer'; import AssetGraph from './AssetGraph'; import BundleGraph from './BundleGraph'; -import Graph from './Graph'; import ParcelConfig from './ParcelConfig'; import {RequestGraph} from './RequestTracker'; import Config from './public/Config'; @@ -107,9 +110,21 @@ const ignoreOptions = new Set([ export function optionsProxy( options: ParcelOptions, invalidateOnOptionChange: string => void, + addDevDependency?: (devDep: InternalDevDepOptions) => void, ): ParcelOptions { + let packageManager = addDevDependency + ? proxyPackageManager( + options.projectRoot, + options.packageManager, + addDevDependency, + ) + : options.packageManager; return new Proxy(options, { get(target, prop) { + if (prop === 'packageManager') { + return packageManager; + } + if (!ignoreOptions.has(prop)) { invalidateOnOptionChange(prop); } @@ -119,6 +134,32 @@ export function optionsProxy( }); } +function proxyPackageManager( + projectRoot: FilePath, + packageManager: PackageManager, + addDevDependency: (devDep: InternalDevDepOptions) => void, +): PackageManager { + let require = (id: string, from: string, opts) => { + addDevDependency({ + specifier: id, + resolveFrom: toProjectPath(projectRoot, from), + range: opts?.range, + }); + return packageManager.require(id, from, opts); + }; + + return new Proxy(packageManager, { + get(target, prop) { + if (prop === 'require') { + return require; + } + + // $FlowFixMe + return target[prop]; + }, + }); +} + export function hashFromOption(value: mixed): string { if (typeof value === 'object' && value != null) { return hashObject(value); diff --git a/packages/core/core/test/AssetGraph.test.js b/packages/core/core/test/AssetGraph.test.js index 4841ce61fe1..ce1ed9e500d 100644 --- a/packages/core/core/test/AssetGraph.test.js +++ b/packages/core/core/test/AssetGraph.test.js @@ -154,12 +154,12 @@ describe('AssetGraph', () => { { from: graph.rootNodeId, to: graph.getNodeIdByContentKey('entry_specifier:path/to/index1'), - type: 0, + type: 1, }, { from: graph.rootNodeId, to: graph.getNodeIdByContentKey('entry_specifier:path/to/index2'), - type: 0, + type: 1, }, { from: graph.getNodeIdByContentKey('entry_specifier:path/to/index1'), @@ -169,7 +169,7 @@ describe('AssetGraph', () => { packagePath: toProjectPath('/path/to/index1'), }).id, ), - type: 0, + type: 1, }, { from: graph.getNodeIdByContentKey('entry_specifier:path/to/index2'), @@ -179,7 +179,7 @@ describe('AssetGraph', () => { packagePath: toProjectPath('/path/to/index2'), }).id, ), - type: 0, + type: 1, }, { from: graph.getNodeIdByContentKey( @@ -196,7 +196,7 @@ describe('AssetGraph', () => { env: DEFAULT_ENV, }).id, ), - type: 0, + type: 1, }, { from: graph.getNodeIdByContentKey( @@ -213,7 +213,7 @@ describe('AssetGraph', () => { env: DEFAULT_ENV, }).id, ), - type: 0, + type: 1, }, ]); }); diff --git a/packages/core/core/test/ParcelConfig.test.js b/packages/core/core/test/ParcelConfig.test.js index e58cfb8190a..54652c86c71 100644 --- a/packages/core/core/test/ParcelConfig.test.js +++ b/packages/core/core/test/ParcelConfig.test.js @@ -289,8 +289,7 @@ describe('ParcelConfig', () => { name: 'Error', diagnostics: [ { - message: - 'Named pipeline `node:` is reserved for builtin Node.js libraries', + message: "Named pipeline 'node:' is reserved.", origin: '@parcel/core', codeFrames: [ { @@ -312,6 +311,8 @@ describe('ParcelConfig', () => { ], }, ], + documentationURL: + 'https://v2.parceljs.org/features/dependency-resolution/#url-schemes', }, ], }, diff --git a/packages/core/core/test/ParcelConfigRequest.test.js b/packages/core/core/test/ParcelConfigRequest.test.js index c656ba6bcdb..8784a3d0143 100644 --- a/packages/core/core/test/ParcelConfigRequest.test.js +++ b/packages/core/core/test/ParcelConfigRequest.test.js @@ -643,6 +643,7 @@ describe('ParcelConfigRequest', () => { runtimes: [], namers: [], optimizers: {}, + compressors: {}, packagers: {}, reporters: [], validators: {}, diff --git a/packages/core/core/test/PublicBundle.test.js b/packages/core/core/test/PublicBundle.test.js index 231b537f687..39fe7baf6ba 100644 --- a/packages/core/core/test/PublicBundle.test.js +++ b/packages/core/core/test/PublicBundle.test.js @@ -2,11 +2,12 @@ import type {Bundle as InternalBundle} from '../src/types'; import assert from 'assert'; +import {ContentGraph} from '@parcel/graph'; + import {Bundle, NamedBundle, PackagedBundle} from '../src/public/Bundle'; import BundleGraph from '../src/BundleGraph'; import {createEnvironment} from '../src/Environment'; import {DEFAULT_OPTIONS} from './test-utils'; -import ContentGraph from '../src/ContentGraph'; import {toProjectPath} from '../src/projectPath'; describe('Public Bundle', () => { diff --git a/packages/core/core/test/TargetRequest.test.js b/packages/core/core/test/TargetRequest.test.js index f96ea289d42..467bc0b1436 100644 --- a/packages/core/core/test/TargetRequest.test.js +++ b/packages/core/core/test/TargetRequest.test.js @@ -736,6 +736,8 @@ describe('TargetResolver', () => { hints: [ 'The "main" field is meant for libraries. If you meant to output a .html file, either remove the "main" field or choose a different target name.', ], + documentationURL: + 'https://v2.parceljs.org/features/targets/#library-targets', }, ], }); @@ -776,6 +778,8 @@ describe('TargetResolver', () => { hints: [ 'The "main" field is meant for libraries. The outputFormat must be either "commonjs" or "esmodule". Either change or remove the declared outputFormat.', ], + documentationURL: + 'https://v2.parceljs.org/features/targets/#library-targets', }, ], }); @@ -827,6 +831,8 @@ describe('TargetResolver', () => { hints: [ 'Either change the output file extension to .mjs, add "type": "module" to package.json, or remove the declared outputFormat.', ], + documentationURL: + 'https://v2.parceljs.org/features/targets/#library-targets', }, ], }); @@ -878,6 +884,8 @@ describe('TargetResolver', () => { hints: [ 'Either remove the target\'s declared "outputFormat" or change the extension to .mjs or .js.', ], + documentationURL: + 'https://v2.parceljs.org/features/targets/#library-targets', }, ], }); @@ -929,6 +937,8 @@ describe('TargetResolver', () => { hints: [ 'Either remove the target\'s declared "outputFormat" or change the extension to .cjs or .js.', ], + documentationURL: + 'https://v2.parceljs.org/features/targets/#library-targets', }, ], }); @@ -968,6 +978,8 @@ describe('TargetResolver', () => { hints: [ 'The "main" target is meant for libraries. Either remove the "scopeHoist" option, or use a different target name.', ], + documentationURL: + 'https://v2.parceljs.org/features/targets/#library-targets', }, ], }); @@ -1016,6 +1028,8 @@ describe('TargetResolver', () => { }, ], hints: ['Either remove the "scopeHoist" or "isLibrary" option.'], + documentationURL: + 'https://v2.parceljs.org/features/targets/#library-targets', }, ], }); diff --git a/packages/core/diagnostic/src/diagnostic.js b/packages/core/diagnostic/src/diagnostic.js index 428578c8ab0..95251b40979 100644 --- a/packages/core/diagnostic/src/diagnostic.js +++ b/packages/core/diagnostic/src/diagnostic.js @@ -69,6 +69,9 @@ export type Diagnostic = {| /** @private */ skipFormatting?: boolean, + + /** A URL to documentation to learn more about the diagnostic. */ + documentationURL?: string, |}; // This type should represent all error formats Parcel can encounter... @@ -293,8 +296,19 @@ export function md( ): string { let result = []; for (let i = 0; i < params.length; i++) { + result.push(strings[i]); + let param = params[i]; - result.push(strings[i], param?.[mdVerbatim] ?? escapeMarkdown(`${param}`)); + if (Array.isArray(param)) { + for (let j = 0; j < param.length; j++) { + result.push(param[j]?.[mdVerbatim] ?? escapeMarkdown(`${param[j]}`)); + if (j < param.length - 1) { + result.push(', '); + } + } + } else { + result.push(param?.[mdVerbatim] ?? escapeMarkdown(`${param}`)); + } } return result.join('') + strings[strings.length - 1]; } diff --git a/packages/core/graph/package.json b/packages/core/graph/package.json new file mode 100644 index 00000000000..48cf3915825 --- /dev/null +++ b/packages/core/graph/package.json @@ -0,0 +1,25 @@ +{ + "name": "@parcel/graph", + "version": "2.0.0-rc.0", + "description": "Blazing fast, zero configuration web application bundler", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "repository": { + "type": "git", + "url": "https://github.com/parcel-bundler/parcel.git" + }, + "main": "lib/index.js", + "source": "src/index.js", + "engines": { + "node": ">= 12.0.0" + }, + "dependencies": { + "nullthrows": "^1.1.1" + } +} diff --git a/packages/core/core/src/ContentGraph.js b/packages/core/graph/src/ContentGraph.js similarity index 100% rename from packages/core/core/src/ContentGraph.js rename to packages/core/graph/src/ContentGraph.js diff --git a/packages/core/core/src/Graph.js b/packages/core/graph/src/Graph.js similarity index 100% rename from packages/core/core/src/Graph.js rename to packages/core/graph/src/Graph.js diff --git a/packages/core/graph/src/index.js b/packages/core/graph/src/index.js new file mode 100644 index 00000000000..a364b030efe --- /dev/null +++ b/packages/core/graph/src/index.js @@ -0,0 +1,6 @@ +// @flow strict-local + +export type {NodeId, ContentKey, Edge} from './types'; +export {toNodeId, fromNodeId} from './types'; +export {default as Graph, ALL_EDGE_TYPES, GraphOpts, mapVisitor} from './Graph'; +export {default as ContentGraph, SerializedContentGraph} from './ContentGraph'; diff --git a/packages/core/graph/src/types.js b/packages/core/graph/src/types.js new file mode 100644 index 00000000000..355f02d08a8 --- /dev/null +++ b/packages/core/graph/src/types.js @@ -0,0 +1,18 @@ +// @flow strict-local + +// forcing NodeId to be opaque as it should only be created once +export opaque type NodeId = number; +export function toNodeId(x: number): NodeId { + return x; +} +export function fromNodeId(x: NodeId): number { + return x; +} + +export type ContentKey = string; + +export type Edge = {| + from: NodeId, + to: NodeId, + type: TEdgeType, +|}; diff --git a/packages/core/core/test/ContentGraph.test.js b/packages/core/graph/test/ContentGraph.test.js similarity index 100% rename from packages/core/core/test/ContentGraph.test.js rename to packages/core/graph/test/ContentGraph.test.js diff --git a/packages/core/core/test/Graph.test.js b/packages/core/graph/test/Graph.test.js similarity index 94% rename from packages/core/core/test/Graph.test.js rename to packages/core/graph/test/Graph.test.js index e46185ff8c3..bbecc3a28ec 100644 --- a/packages/core/core/test/Graph.test.js +++ b/packages/core/graph/test/Graph.test.js @@ -114,7 +114,7 @@ describe('Graph', () => { assert(graph.nodes.has(nodeD)); assert(!graph.nodes.has(nodeB)); assert(!graph.nodes.has(nodeC)); - assert.deepEqual(graph.getAllEdges(), [{from: nodeA, to: nodeD, type: 0}]); + assert.deepEqual(graph.getAllEdges(), [{from: nodeA, to: nodeD, type: 1}]); }); it('removing a node recursively deletes orphaned nodes', () => { @@ -155,8 +155,8 @@ describe('Graph', () => { assert.deepEqual([...graph.nodes.keys()], [nodeA, nodeC, nodeF]); assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeC, type: 0}, - {from: nodeC, to: nodeF, type: 0}, + {from: nodeA, to: nodeC, type: 1}, + {from: nodeC, to: nodeF, type: 1}, ]); }); @@ -200,8 +200,8 @@ describe('Graph', () => { assert.deepEqual([...graph.nodes.keys()], [nodeA, nodeC, nodeF]); assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeC, type: 0}, - {from: nodeC, to: nodeF, type: 0}, + {from: nodeA, to: nodeC, type: 1}, + {from: nodeC, to: nodeF, type: 1}, ]); }); @@ -235,11 +235,11 @@ describe('Graph', () => { assert.deepEqual(nodesBefore, getNodeIds()); assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeB, type: 0}, - {from: nodeB, to: nodeC, type: 0}, - {from: nodeB, to: nodeD, type: 0}, - {from: nodeD, to: nodeE, type: 0}, - {from: nodeE, to: nodeB, type: 0}, + {from: nodeA, to: nodeB, type: 1}, + {from: nodeB, to: nodeC, type: 1}, + {from: nodeB, to: nodeD, type: 1}, + {from: nodeD, to: nodeE, type: 1}, + {from: nodeE, to: nodeB, type: 1}, ]); }); @@ -278,8 +278,8 @@ describe('Graph', () => { assert(!graph.hasNode(nodeC)); assert(graph.hasNode(nodeD)); assert.deepEqual(graph.getAllEdges(), [ - {from: nodeA, to: nodeB, type: 0}, - {from: nodeA, to: nodeD, type: 0}, + {from: nodeA, to: nodeB, type: 1}, + {from: nodeA, to: nodeD, type: 1}, ]); }); @@ -290,10 +290,10 @@ describe('Graph', () => { let nodeC = graph.addNode('c'); let nodeD = graph.addNode('d'); - graph.addEdge(nodeA, nodeB, 1); + graph.addEdge(nodeA, nodeB, 2); graph.addEdge(nodeA, nodeD); graph.addEdge(nodeB, nodeC); - graph.addEdge(nodeB, nodeD, 1); + graph.addEdge(nodeB, nodeD, 2); graph.setRootNodeId(nodeA); @@ -303,7 +303,7 @@ describe('Graph', () => { visited.push(nodeId); }, null, // use root as startNode - 1, + 2, ); assert.deepEqual(visited, [nodeA, nodeB, nodeD]); diff --git a/packages/core/integration-tests/package.json b/packages/core/integration-tests/package.json index adb78208f59..00185cbecc6 100644 --- a/packages/core/integration-tests/package.json +++ b/packages/core/integration-tests/package.json @@ -26,7 +26,7 @@ "command-exists": "^1.2.6", "core-js": "^3.2.1", "cross-env": "^7.0.0", - "elm": "^0.19.1-3", + "elm": "^0.19.1-5", "elm-hot": "^1.1.5", "get-port": "^5.0.0", "graphql": "^15.0.0", diff --git a/packages/core/integration-tests/test/babel.js b/packages/core/integration-tests/test/babel.js index b09ab2a95e0..09fe260eb6f 100644 --- a/packages/core/integration-tests/test/babel.js +++ b/packages/core/integration-tests/test/babel.js @@ -16,6 +16,7 @@ import Logger from '@parcel/logger'; import os from 'os'; import {spawnSync} from 'child_process'; import tempy from 'tempy'; +import {md} from '@parcel/diagnostic'; const parcelCli = require.resolve('parcel/src/bin.js'); const inputDir = path.join(__dirname, '/input'); @@ -568,4 +569,138 @@ describe('babel', function() { assert(!file.includes('interface')); assert(file.includes('React.createElement')); }); + + it('should warn when a babel config contains only redundant plugins', async function() { + let messages = []; + let loggerDisposable = Logger.onLog(message => { + messages.push(message); + }); + let filePath = path.join(__dirname, '/integration/babel-warn-all/index.js'); + await bundle(filePath); + loggerDisposable.dispose(); + + let babelrcPath = path.resolve(path.dirname(filePath), '.babelrc'); + assert.deepEqual(messages, [ + { + type: 'log', + level: 'warn', + diagnostics: [ + { + origin: '@parcel/transformer-babel', + message: md`Parcel includes transpilation by default. Babel config __${path.relative( + process.cwd(), + babelrcPath, + )}__ contains only redundant presets. Deleting it may significantly improve build performance.`, + codeFrames: [ + { + filePath: babelrcPath, + codeHighlights: [ + { + message: undefined, + start: { + line: 2, + column: 15, + }, + end: { + line: 2, + column: 33, + }, + }, + ], + }, + ], + hints: [ + md`Delete __${path.relative(process.cwd(), babelrcPath)}__`, + ], + documentationURL: + 'https://v2.parceljs.org/languages/javascript/#default-presets', + }, + { + origin: '@parcel/transformer-babel', + message: + "@babel/preset-env does not support Parcel's targets, which will likely result in unnecessary transpilation and larger bundle sizes.", + codeFrames: [ + { + filePath: path.resolve(path.dirname(filePath), '.babelrc'), + codeHighlights: [ + { + message: undefined, + start: { + line: 2, + column: 15, + }, + end: { + line: 2, + column: 33, + }, + }, + ], + }, + ], + hints: [ + "Either remove __@babel/preset-env__ to use Parcel's builtin transpilation, or replace with __@parcel/babel-preset-env__", + ], + documentationURL: + 'https://v2.parceljs.org/languages/javascript/#custom-plugins', + }, + ], + }, + ]); + }); + + it('should warn when a babel config contains redundant plugins', async function() { + let messages = []; + let loggerDisposable = Logger.onLog(message => { + messages.push(message); + }); + let filePath = path.join( + __dirname, + '/integration/babel-warn-some/index.js', + ); + await bundle(filePath); + loggerDisposable.dispose(); + + let babelrcPath = path.resolve(path.dirname(filePath), '.babelrc'); + assert.deepEqual(messages, [ + { + type: 'log', + level: 'warn', + diagnostics: [ + { + origin: '@parcel/transformer-babel', + message: md`Parcel includes transpilation by default. Babel config __${path.relative( + process.cwd(), + babelrcPath, + )}__ includes the following redundant presets: __@parcel/babel-preset-env__. Removing these may improve build performance.`, + codeFrames: [ + { + filePath: babelrcPath, + codeHighlights: [ + { + message: undefined, + start: { + line: 2, + column: 15, + }, + end: { + line: 2, + column: 40, + }, + }, + ], + }, + ], + hints: [ + md`Remove the above presets from __${path.relative( + process.cwd(), + babelrcPath, + )}__`, + ], + documentationURL: + 'https://v2.parceljs.org/languages/javascript/#default-presets', + }, + ], + }, + ]); + }); }); diff --git a/packages/core/integration-tests/test/cache.js b/packages/core/integration-tests/test/cache.js index ca00b2c9a9c..ab8b81980aa 100644 --- a/packages/core/integration-tests/test/cache.js +++ b/packages/core/integration-tests/test/cache.js @@ -8,6 +8,7 @@ import { bundler, run, overlayFS, + outputFS, inputFS, ncp, workerFarm, @@ -3077,9 +3078,9 @@ describe('cache', function() { describe('pnp', function() { it('should invalidate when the .pnp.js file changes', async function() { - // $FlowFixMe let Module = require('module'); let origPnpVersion = process.versions.pnp; + // $FlowFixMe[prop-missing] let origModuleResolveFilename = Module._resolveFilename; try { @@ -3094,9 +3095,10 @@ describe('cache', function() { inputDir, ); - // $FlowFixMe + // $FlowFixMe[incompatible-type] process.versions.pnp = 42; + // $FlowFixMe[prop-missing] Module.findPnpApi = () => // $FlowFixMe require(path.join(inputDir, '.pnp.js')); @@ -3130,7 +3132,9 @@ describe('cache', function() { let output = await run(b.bundleGraph); assert.equal(output(), 6); } finally { + // $FlowFixMe[incompatible-type] process.versions.pnp = origPnpVersion; + // $FlowFixMe[prop-missing] Module._resolveFilename = origModuleResolveFilename; } }); @@ -3611,6 +3615,59 @@ describe('cache', function() { assert(output.includes('UPDATED')); }); + it('should invalidate when updating a file required via options.packageManager.require', async function() { + let b = await testCache({ + async setup() { + await overlayFS.writeFile( + path.join(inputDir, '.parcelrc'), + JSON.stringify({ + extends: '@parcel/config-default', + transformers: { + '*.js': ['parcel-transformer-mock'], + }, + }), + ); + let transformer = path.join( + inputDir, + 'node_modules', + 'parcel-transformer-mock', + 'index.js', + ); + let contents = await overlayFS.readFile(transformer, 'utf8'); + await overlayFS.writeFile( + transformer, + contents + .replace( + 'transform({asset}) {', + 'async transform({asset, options}) {', + ) + .replace( + "const {message} = require('./constants');", + "const message = 'FOO: ' + await options.packageManager.require('foo', asset.filePath);", + ), + ); + }, + async update(b) { + let output = await overlayFS.readFile( + b.bundleGraph.getBundles()[0].filePath, + 'utf8', + ); + assert(output.includes('FOO: 2')); + + await overlayFS.writeFile( + path.join(inputDir, 'node_modules', 'foo', 'foo.js'), + 'module.exports = 3;', + ); + }, + }); + + let output = await overlayFS.readFile( + b.bundleGraph.getBundles()[0].filePath, + 'utf8', + ); + assert(output.includes('FOO: 3')); + }); + it('should resolve to package.json#main over an index.js', async function() { let b = await testCache({ async setup() { @@ -3716,9 +3773,10 @@ describe('cache', function() { it('should support adding a deeper node_modules folder', async function() {}); it('should support yarn pnp', async function() { - // $FlowFixMe let Module = require('module'); + // $FlowFixMe[incompatible-type] let origPnpVersion = process.versions.pnp; + // $FlowFixMe[prop-missing] let origModuleResolveFilename = Module._resolveFilename; // We must create a worker farm that only uses a single thread because our process.versions.pnp @@ -3809,6 +3867,7 @@ describe('cache', function() { `, ); + // $FlowFixMe[prop-missing] Module.findPnpApi = () => // $FlowFixMe require(path.join(inputDir, '.pnp.js')); @@ -3860,6 +3919,7 @@ describe('cache', function() { assert(output.includes('UPDATED')); } finally { process.versions.pnp = origPnpVersion; + // $FlowFixMe[prop-missing] Module._resolveFilename = origModuleResolveFilename; await workerFarm.end(); } @@ -5373,6 +5433,80 @@ describe('cache', function() { }); }); + describe('compression', function() { + it('should invaldate when adding a compressor plugin', async function() { + await testCache({ + async update() { + let files = await outputFS.readdir(distDir); + assert.deepEqual(files.sort(), ['index.js', 'index.js.map']); + + await overlayFS.writeFile( + path.join(inputDir, '.parcelrc'), + JSON.stringify({ + extends: '@parcel/config-default', + compressors: { + '*.js': ['...', '@parcel/compressor-gzip'], + }, + }), + ); + }, + }); + + let files = await outputFS.readdir(distDir); + assert.deepEqual(files.sort(), [ + 'index.js', + 'index.js.gz', + 'index.js.map', + ]); + }); + + it('should invalidate when updating a compressor plugin', async function() { + await testCache({ + async setup() { + await overlayFS.writeFile( + path.join(inputDir, '.parcelrc'), + JSON.stringify({ + extends: '@parcel/config-default', + compressors: { + '*.js': ['...', 'parcel-compressor-test'], + }, + }), + ); + }, + async update() { + let files = await outputFS.readdir(distDir); + assert.deepEqual(files.sort(), [ + 'index.js', + 'index.js.abc', + 'index.js.map', + ]); + + let compressor = path.join( + inputDir, + 'node_modules', + 'parcel-compressor-test', + 'index.js', + ); + await overlayFS.writeFile( + compressor, + (await overlayFS.readFile(compressor, 'utf8')).replace( + 'abc', + 'def', + ), + ); + }, + }); + + let files = await outputFS.readdir(distDir); + assert.deepEqual(files.sort(), [ + 'index.js', + 'index.js.abc', + 'index.js.def', + 'index.js.map', + ]); + }); + }); + describe('scope hoisting', function() { it('should support adding sideEffects config', function() {}); diff --git a/packages/core/integration-tests/test/compressors.js b/packages/core/integration-tests/test/compressors.js new file mode 100644 index 00000000000..4bdf229b8c7 --- /dev/null +++ b/packages/core/integration-tests/test/compressors.js @@ -0,0 +1,36 @@ +import assert from 'assert'; +import path from 'path'; +import zlib from 'zlib'; +import {bundle, outputFS, distDir} from '@parcel/test-utils'; + +describe('compressors', function() { + it('should compress output with gzip and brotli', async function() { + await bundle(path.join(__dirname, 'integration/compressors/index.js')); + + let output = await outputFS.readdir(distDir); + assert.deepEqual(output.sort(), [ + 'index.js', + 'index.js.br', + 'index.js.gz', + 'index.js.map', + 'index.js.map.br', + 'index.js.map.gz', + ]); + + let raw = await outputFS.readFile(path.join(distDir, 'index.js')); + let gz = await outputFS.readFile(path.join(distDir, 'index.js.gz')); + let br = await outputFS.readFile(path.join(distDir, 'index.js.br')); + + assert(zlib.gunzipSync(gz).equals(raw)); + assert(zlib.brotliDecompressSync(br).equals(raw)); + }); + + it('should be able to disable raw output', async function() { + await bundle( + path.join(__dirname, 'integration/compressors-disable-default/index.js'), + ); + + let output = await outputFS.readdir(distDir); + assert.deepEqual(output.sort(), ['index.js.br', 'index.js.map.br']); + }); +}); diff --git a/packages/core/integration-tests/test/css.js b/packages/core/integration-tests/test/css.js index a9b46c6484f..d14513c48ff 100644 --- a/packages/core/integration-tests/test/css.js +++ b/packages/core/integration-tests/test/css.js @@ -319,7 +319,7 @@ describe('css', () => { assert.equal( css.trim(), `.svg-img { - background-image: url('data:image/svg+xml,%3Csvg%20width%3D%22120%22%20height%3D%27120%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Cfilter%20id%3D%22blur-_.%21~%2a%22%3E%0A%20%20%20%20%3CfeGaussianBlur%20stdDeviation%3D%225%22%2F%3E%0A%20%20%3C%2Ffilter%3E%0A%20%20%3Ccircle%20cx%3D%2260%22%20cy%3D%2260%22%20r%3D%2250%22%20fill%3D%22green%22%20filter%3D%22url%28%23blur-_.%21~%2a%29%22%20%2F%3E%0A%3C%2Fsvg%3E%0A'); + background-image: url('data:image/svg+xml,%3Csvg%20width%3D%22120%22%20height%3D%22120%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Cfilter%20id%3D%22blur-_.%21~%2a%22%3E%0A%20%20%20%20%3CfeGaussianBlur%20stdDeviation%3D%225%22%3E%3C%2FfeGaussianBlur%3E%0A%20%20%3C%2Ffilter%3E%0A%20%20%3Ccircle%20cx%3D%2260%22%20cy%3D%2260%22%20r%3D%2250%22%20fill%3D%22green%22%20filter%3D%22url%28%27%23blur-_.%21~%2a%27%29%22%3E%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A'); }`, ); }); @@ -381,4 +381,41 @@ describe('css', () => { }, ); }); + + it('should support importing CSS from node_modules with the npm: scheme', async () => { + let b = await bundle( + path.join(__dirname, '/integration/css-node-modules/index.css'), + ); + + assertBundles(b, [ + { + name: 'index.css', + assets: ['index.css', 'foo.css'], + }, + ]); + }); + + it('should support external CSS imports', async () => { + let b = await bundle( + path.join(__dirname, '/integration/css-external/a.css'), + ); + + assertBundles(b, [ + { + name: 'a.css', + assets: ['a.css', 'b.css'], + }, + ]); + + let res = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8'); + assert( + res.startsWith(`@import "http://example.com/external.css"; +.b { + color: red; +} +.a { + color: blue; +}`), + ); + }); }); diff --git a/packages/core/integration-tests/test/html.js b/packages/core/integration-tests/test/html.js index b2490f7cfb4..990a8344088 100644 --- a/packages/core/integration-tests/test/html.js +++ b/packages/core/integration-tests/test/html.js @@ -170,7 +170,7 @@ describe('html', function() { assert(//.test(html)); }); - it('should support meta tag with none content', async function() { + it('should support meta tags', async function() { let b = await bundle( path.join(__dirname, '/integration/html-meta/index.html'), ); @@ -180,13 +180,23 @@ describe('html', function() { name: 'index.html', assets: ['index.html'], }, + { + name: 'logo.svg', + assets: ['logo.svg'], + }, ]); let html = await outputFS.readFile( path.join(distDir, 'index.html'), 'utf8', ); - assert(//.test(html)); + assert(html.includes(``)); + assert(html.includes(``)); + assert( + html.includes( + ``, + ), + ); }); it('should insert sibling CSS bundles for JS files in the HEAD', async function() { @@ -1243,6 +1253,8 @@ describe('html', function() { }, ], hints: ['Add the type="module" attribute to the + diff --git a/packages/core/integration-tests/test/integration/svg-inline-css-import/test.css b/packages/core/integration-tests/test/integration/svg-inline-css-import/test.css new file mode 100644 index 00000000000..cfde1a8c325 --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg-inline-css-import/test.css @@ -0,0 +1,3 @@ +:root { + fill: red +} diff --git a/packages/core/integration-tests/test/integration/svg-inline-sass/img.svg b/packages/core/integration-tests/test/integration/svg-inline-sass/img.svg new file mode 100644 index 00000000000..25729e664cf --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg-inline-sass/img.svg @@ -0,0 +1,7 @@ + + + Should be red + diff --git a/packages/core/integration-tests/test/integration/svg-multiple/circle.svg b/packages/core/integration-tests/test/integration/svg-multiple/circle.svg new file mode 100644 index 00000000000..312b4137553 --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg-multiple/circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/core/integration-tests/test/integration/svg-multiple/index.js b/packages/core/integration-tests/test/integration/svg-multiple/index.js new file mode 100644 index 00000000000..da16cc9827c --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg-multiple/index.js @@ -0,0 +1,2 @@ +import "./circle.svg"; +import "./square.svg"; diff --git a/packages/core/integration-tests/test/integration/svg-multiple/square.svg b/packages/core/integration-tests/test/integration/svg-multiple/square.svg new file mode 100644 index 00000000000..1fbcd5a72d0 --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg-multiple/square.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/core/integration-tests/test/integration/svg/icon.svg b/packages/core/integration-tests/test/integration/svg-react/icon.svg similarity index 100% rename from packages/core/integration-tests/test/integration/svg/icon.svg rename to packages/core/integration-tests/test/integration/svg-react/icon.svg diff --git a/packages/core/integration-tests/test/integration/svg/index.html b/packages/core/integration-tests/test/integration/svg-react/index.html similarity index 100% rename from packages/core/integration-tests/test/integration/svg/index.html rename to packages/core/integration-tests/test/integration/svg-react/index.html diff --git a/packages/core/integration-tests/test/integration/svg/package.json b/packages/core/integration-tests/test/integration/svg-react/package.json similarity index 100% rename from packages/core/integration-tests/test/integration/svg/package.json rename to packages/core/integration-tests/test/integration/svg-react/package.json diff --git a/packages/core/integration-tests/test/integration/svg/react.js b/packages/core/integration-tests/test/integration/svg-react/react.js similarity index 100% rename from packages/core/integration-tests/test/integration/svg/react.js rename to packages/core/integration-tests/test/integration/svg-react/react.js diff --git a/packages/core/integration-tests/test/integration/svg-xml-stylesheet/img.svg b/packages/core/integration-tests/test/integration/svg-xml-stylesheet/img.svg new file mode 100644 index 00000000000..e2dcb3c0a7e --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg-xml-stylesheet/img.svg @@ -0,0 +1,11 @@ + + + + + + Should be red and monospace + diff --git a/packages/core/integration-tests/test/integration/svg-xml-stylesheet/style1.css b/packages/core/integration-tests/test/integration/svg-xml-stylesheet/style1.css new file mode 100644 index 00000000000..4c6d8c9b1c8 --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg-xml-stylesheet/style1.css @@ -0,0 +1,4 @@ +:root { + fill: red; + font-family: serif; +} diff --git a/packages/core/integration-tests/test/integration/svg-xml-stylesheet/style2.css b/packages/core/integration-tests/test/integration/svg-xml-stylesheet/style2.css new file mode 100644 index 00000000000..d3e88e2a234 --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg-xml-stylesheet/style2.css @@ -0,0 +1,3 @@ +:root { + font-family: sans-serif; +} diff --git a/packages/core/integration-tests/test/integration/svg-xml-stylesheet/style3.css b/packages/core/integration-tests/test/integration/svg-xml-stylesheet/style3.css new file mode 100644 index 00000000000..f4523b098a4 --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg-xml-stylesheet/style3.css @@ -0,0 +1,3 @@ +:root { + font-family: monospace; +} diff --git a/packages/core/integration-tests/test/integration/svg-xml-stylesheet/style4.css b/packages/core/integration-tests/test/integration/svg-xml-stylesheet/style4.css new file mode 100644 index 00000000000..2b5e3e9f641 --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg-xml-stylesheet/style4.css @@ -0,0 +1,3 @@ +:root { + font-family: cursive; +} diff --git a/packages/core/integration-tests/test/integration/svg/circle.svg b/packages/core/integration-tests/test/integration/svg/circle.svg new file mode 100644 index 00000000000..9a99def24bb --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg/circle.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + Quick brown fox jumps over the lazy dog. + + + + + diff --git a/packages/core/integration-tests/test/integration/svg/gradient.svg b/packages/core/integration-tests/test/integration/svg/gradient.svg new file mode 100644 index 00000000000..0542f48eddb --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg/gradient.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packages/core/integration-tests/test/integration/svg/module.js b/packages/core/integration-tests/test/integration/svg/module.js new file mode 100644 index 00000000000..61f90cdfb52 --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg/module.js @@ -0,0 +1,3 @@ +import './style.css'; +import './script'; +console.log('module'); diff --git a/packages/core/integration-tests/test/integration/svg/other1.html b/packages/core/integration-tests/test/integration/svg/other1.html new file mode 100644 index 00000000000..f4ae7dea450 --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg/other1.html @@ -0,0 +1,2 @@ + +Other page 1 diff --git a/packages/core/integration-tests/test/integration/svg/other2.html b/packages/core/integration-tests/test/integration/svg/other2.html new file mode 100644 index 00000000000..7c40cf0f3bf --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg/other2.html @@ -0,0 +1,2 @@ + +Other page 2 diff --git a/packages/core/integration-tests/test/integration/svg/path.svg b/packages/core/integration-tests/test/integration/svg/path.svg new file mode 100644 index 00000000000..cf31460cd43 --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg/path.svg @@ -0,0 +1,6 @@ + + + + + diff --git a/packages/core/integration-tests/test/integration/svg/script.js b/packages/core/integration-tests/test/integration/svg/script.js new file mode 100644 index 00000000000..a6a223c0ab1 --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg/script.js @@ -0,0 +1 @@ +console.log('script'); diff --git a/packages/core/integration-tests/test/integration/svg/square.svg b/packages/core/integration-tests/test/integration/svg/square.svg new file mode 100644 index 00000000000..af1ab4adf39 --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg/square.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/core/integration-tests/test/integration/svg/style.css b/packages/core/integration-tests/test/integration/svg/style.css new file mode 100644 index 00000000000..cb771a383a0 --- /dev/null +++ b/packages/core/integration-tests/test/integration/svg/style.css @@ -0,0 +1,3 @@ +circle { + fill: red; +} diff --git a/packages/core/integration-tests/test/integration/swc-helpers/yarn.lock b/packages/core/integration-tests/test/integration/swc-helpers/yarn.lock new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/integration-tests/test/integration/worklet/colors.js b/packages/core/integration-tests/test/integration/worklet/colors.js new file mode 100644 index 00000000000..69d0953d465 --- /dev/null +++ b/packages/core/integration-tests/test/integration/worklet/colors.js @@ -0,0 +1 @@ +export const colors = ['red', 'green', 'blue']; diff --git a/packages/core/integration-tests/test/integration/worklet/worklet-pipeline.js b/packages/core/integration-tests/test/integration/worklet/worklet-pipeline.js index 8a7ff4d129f..680f46d29b7 100644 --- a/packages/core/integration-tests/test/integration/worklet/worklet-pipeline.js +++ b/packages/core/integration-tests/test/integration/worklet/worklet-pipeline.js @@ -1,2 +1,2 @@ import url from 'worklet:./worklet'; -export default url; +output = url; diff --git a/packages/core/integration-tests/test/integration/worklet/worklet.js b/packages/core/integration-tests/test/integration/worklet/worklet.js index 12cdab6833f..c71984e3c11 100644 --- a/packages/core/integration-tests/test/integration/worklet/worklet.js +++ b/packages/core/integration-tests/test/integration/worklet/worklet.js @@ -1,8 +1,9 @@ +import {colors} from './colors'; + // checkerboard.js class CheckerboardPainter { paint(ctx, geom, properties) { // Use "ctx" as if it was a normal canvas - const colors = ['red', 'green', 'blue']; const size = 32; for(let y = 0; y < geom.height/size; y++) { for(let x = 0; x < geom.width/size; x++) { diff --git a/packages/core/integration-tests/test/javascript.js b/packages/core/integration-tests/test/javascript.js index 5f948d2abd3..b9189a79169 100644 --- a/packages/core/integration-tests/test/javascript.js +++ b/packages/core/integration-tests/test/javascript.js @@ -62,16 +62,19 @@ describe('javascript', function() { it('should support url: imports of another javascript file', async function() { let b = await bundle( path.join(__dirname, '/integration/worklet/pipeline.js'), + { + mode: 'production', + }, ); assertBundles(b, [ { name: 'pipeline.js', - assets: ['bundle-url.js', 'pipeline.js', 'esmodule-helpers.js'], + assets: ['bundle-url.js', 'pipeline.js', 'bundle-manifest.js'], }, { type: 'js', - assets: ['worklet.js'], + assets: ['worklet.js', 'colors.js'], }, ]); @@ -112,7 +115,7 @@ describe('javascript', function() { }, { type: 'js', - assets: ['worklet.js'], + assets: ['worklet.js', 'colors.js', 'esmodule-helpers.js'], }, ]); @@ -146,7 +149,7 @@ describe('javascript', function() { }, { type: 'js', - assets: ['worklet.js'], + assets: ['worklet.js', 'colors.js', 'esmodule-helpers.js'], }, ]); @@ -240,21 +243,24 @@ describe('javascript', function() { it('should support audio worklets via a pipeline', async function() { let b = await bundle( path.join(__dirname, '/integration/worklet/worklet-pipeline.js'), + { + mode: 'production', + }, ); assertBundles(b, [ { name: 'worklet-pipeline.js', - assets: ['bundle-url.js', 'esmodule-helpers.js', 'worklet-pipeline.js'], + assets: ['bundle-url.js', 'bundle-manifest.js', 'worklet-pipeline.js'], }, { type: 'js', - assets: ['worklet.js'], + assets: ['worklet.js', 'colors.js'], }, ]); let res = await run(b); - assert(/^http:\/\/localhost\/worklet\.[0-9a-f]+\.js$/.test(res.default)); + assert(/^http:\/\/localhost\/worklet\.[0-9a-f]+\.js$/.test(res)); let name; await runBundle( @@ -1255,6 +1261,8 @@ describe('javascript', function() { hints: [ "Add {type: 'module'} as a second argument to the Worker constructor.", ], + documentationURL: + 'https://v2.parceljs.org/languages/javascript/#classic-scripts', }, ]); } @@ -1304,11 +1312,12 @@ describe('javascript', function() { errored = true; assert.equal( err.message, - 'importScripts() is not supported in worker scripts.', + 'Argument to importScripts() must be a fully qualified URL.', ); assert.deepEqual(err.diagnostics, [ { - message: 'importScripts() is not supported in worker scripts.', + message: + 'Argument to importScripts() must be a fully qualified URL.', origin: '@parcel/transformer-js', codeFrames: [ { @@ -1321,11 +1330,11 @@ describe('javascript', function() { message: null, start: { line: 1, - column: 1, + column: 15, }, end: { line: 1, - column: 28, + column: 27, }, }, ], @@ -1357,6 +1366,8 @@ describe('javascript', function() { ? 'Worker constructor.' : 'navigator.serviceWorker.register() call.'), ], + documentationURL: + 'https://v2.parceljs.org/languages/javascript/#classic-script-workers', }, ]); } @@ -1407,6 +1418,29 @@ describe('javascript', function() { assert(res.includes('importScripts(url)')); }); + it('should ignore importScripts in script workers a fully qualified URL is provided', async function() { + let b = await bundle( + path.join( + __dirname, + '/integration/worker-import-scripts/index-external.js', + ), + ); + + assertBundles(b, [ + { + type: 'js', + assets: ['index-external.js', 'bundle-url.js', 'get-worker-url.js'], + }, + { + type: 'js', + assets: ['external.js'], + }, + ]); + + let res = await outputFS.readFile(b.getBundles()[1].filePath, 'utf8'); + assert(res.includes("importScripts('https://unpkg.com/parcel')")); + }); + it('should support bundling service-workers', async function() { let b = await bundle( path.join(__dirname, '/integration/service-worker/a/index.js'), @@ -1550,6 +1584,8 @@ describe('javascript', function() { hints: [ "Add {type: 'module'} as a second argument to the navigator.serviceWorker.register() call.", ], + documentationURL: + 'https://v2.parceljs.org/languages/javascript/#classic-scripts', }, ]); } @@ -1557,6 +1593,39 @@ describe('javascript', function() { assert(errored); }); + it('should expose a manifest to service workers', async function() { + let b = await bundle( + path.join(__dirname, '/integration/service-worker/manifest.js'), + { + defaultTargetOptions: { + shouldScopeHoist: true, + }, + }, + ); + + assertBundles(b, [ + { + name: 'manifest.js', + assets: ['manifest.js', 'bundle-url.js'], + }, + { + assets: ['manifest-worker.js', 'service-worker.js'], + }, + ]); + + let bundles = b.getBundles(); + let worker = bundles.find(b => b.env.isWorker()); + let manifest, version; + await await runBundle(b, worker, { + output(m, v) { + manifest = m; + version = v; + }, + }); + assert.deepEqual(manifest, ['/manifest.js']); + assert.equal(typeof version, 'string'); + }); + it('should recognize serviceWorker.register with static URL and import.meta.url', async function() { let b = await bundle( path.join( @@ -1619,6 +1688,69 @@ describe('javascript', function() { }); }); + it('should error on dynamic import() inside service workers', async function() { + let errored = false; + try { + await bundle( + path.join( + __dirname, + '/integration/service-worker/dynamic-import-index.js', + ), + ); + } catch (err) { + errored = true; + assert.equal(err.message, 'import() is not allowed in service workers.'); + assert.deepEqual(err.diagnostics, [ + { + message: 'import() is not allowed in service workers.', + origin: '@parcel/transformer-js', + codeFrames: [ + { + filePath: path.join( + __dirname, + '/integration/service-worker/dynamic-import.js', + ), + codeHighlights: [ + { + start: { + line: 1, + column: 8, + }, + end: { + line: 1, + column: 27, + }, + }, + ], + }, + { + filePath: path.join( + __dirname, + 'integration/service-worker/dynamic-import-index.js', + ), + codeHighlights: [ + { + message: 'The environment was originally created here', + start: { + line: 1, + column: 42, + }, + end: { + line: 1, + column: 60, + }, + }, + ], + }, + ], + hints: ['Try using a static `import`.'], + }, + ]); + } + + assert(errored); + }); + it('should support bundling workers with circular dependencies', async function() { let b = await bundle( path.join(__dirname, '/integration/worker-circular/index.js'), @@ -3960,6 +4092,48 @@ describe('javascript', function() { background-color: #000000; } +.svg-img { + background-image: url("data:image/svg+xml,%3Csvg%3E%0A%0A%3C%2Fsvg%3E%0A"); +}`, + ), + ); + + assert(!cssBundleContent.includes('sourceMappingURL')); + }); + + it('should not include the runtime manifest for `bundle-text`', async () => { + let b = await bundle( + path.join(__dirname, '/integration/bundle-text/index.js'), + { + mode: 'production', + defaultTargetOptions: {shouldScopeHoist: false, shouldOptimize: false}, + }, + ); + + assertBundles(b, [ + { + name: 'index.js', + type: 'js', + assets: ['esmodule-helpers.js', 'index.js'], + }, + { + type: 'svg', + assets: ['img.svg'], + }, + { + type: 'css', + assets: ['text.scss'], + }, + ]); + + let cssBundleContent = (await run(b)).default; + + assert( + cssBundleContent.startsWith( + `body { + background-color: #000000; +} + .svg-img { background-image: url("data:image/svg+xml,%3Csvg%3E%0A%0A%3C%2Fsvg%3E%0A"); }`, @@ -4011,6 +4185,27 @@ describe('javascript', function() { assert.equal(log, 'hi'); }); + it("should inline a JS bundle's compiled text with `bundle-text` with symbol propagation", async () => { + let b = await bundle( + path.join(__dirname, '/integration/bundle-text/javascript.js'), + { + mode: 'production', + }, + ); + + let res = await run(b); + let log; + let ctx = vm.createContext({ + console: { + log(x) { + log = x; + }, + }, + }); + vm.runInContext(res, ctx); + assert.equal(log, 'hi'); + }); + it("should inline a bundle's compiled text with `bundle-text` asynchronously", async () => { let b = await bundle( path.join(__dirname, '/integration/bundle-text/async.js'), @@ -4041,7 +4236,7 @@ describe('javascript', function() { assert.equal( (await run(b)).default, - 'data:image/svg+xml,%3Csvg%20width%3D%22120%22%20height%3D%27120%27%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Cfilter%20id%3D%22blur-_.%21~%2a%22%3E%0A%20%20%20%20%3CfeGaussianBlur%20stdDeviation%3D%225%22%2F%3E%0A%20%20%3C%2Ffilter%3E%0A%20%20%3Ccircle%20cx%3D%2260%22%20cy%3D%2260%22%20r%3D%2250%22%20fill%3D%22green%22%20filter%3D%22url%28%23blur-_.%21~%2a%29%22%20%2F%3E%0A%3C%2Fsvg%3E%0A', + 'data:image/svg+xml,%3Csvg%20width%3D%22120%22%20height%3D%22120%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Cfilter%20id%3D%22blur-_.%21~%2a%22%3E%0A%20%20%20%20%3CfeGaussianBlur%20stdDeviation%3D%225%22%3E%3C%2FfeGaussianBlur%3E%0A%20%20%3C%2Ffilter%3E%0A%20%20%3Ccircle%20cx%3D%2260%22%20cy%3D%2260%22%20r%3D%2250%22%20fill%3D%22green%22%20filter%3D%22url%28%27%23blur-_.%21~%2a%27%29%22%3E%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A', ); }); @@ -4571,7 +4766,7 @@ describe('javascript', function() { name: 'BuildError', diagnostics: [ { - message: 'Unknown pipeline: strange-pipeline.', + message: "Failed to resolve 'strange-pipeline:./b.js' from './a.js'", origin: '@parcel/core', codeFrames: [ { @@ -4592,6 +4787,10 @@ describe('javascript', function() { }, ], }, + { + message: "Unknown url scheme or pipeline 'strange-pipeline:'", + origin: '@parcel/resolver-default', + }, ], }); }); diff --git a/packages/core/integration-tests/test/scope-hoisting.js b/packages/core/integration-tests/test/scope-hoisting.js index 0118744826c..39c215b3ae4 100644 --- a/packages/core/integration-tests/test/scope-hoisting.js +++ b/packages/core/integration-tests/test/scope-hoisting.js @@ -3714,6 +3714,28 @@ describe('scope hoisting', function() { let test = await run(b); assert.equal(test({foo: 2}), 2); }); + + it('should not include default when reexporting * without $parcel$exportWildcard', async () => { + let b = await bundle( + path.join( + __dirname, + 'integration/scope-hoisting/es6/no-reexport-default/index.js', + ), + ); + + assert.equal(await run(b), 42); + }); + + it('should not include __esModule when reexporting * without $parcel$exportWildcard', async () => { + let b = await bundle( + path.join( + __dirname, + 'integration/scope-hoisting/es6/no-reexport-esmodule/index.js', + ), + ); + + assert.equal(await run(b), undefined); + }); }); describe('commonjs', function() { diff --git a/packages/core/integration-tests/test/svg-react.js b/packages/core/integration-tests/test/svg-react.js new file mode 100644 index 00000000000..4de2d507c93 --- /dev/null +++ b/packages/core/integration-tests/test/svg-react.js @@ -0,0 +1,22 @@ +import assert from 'assert'; +import {bundle, outputFS} from '@parcel/test-utils'; +import path from 'path'; + +describe('svg-react', function() { + it('should support transforming SVGs to react components', async function() { + let b = await bundle( + path.join(__dirname, '/integration/svg-react/react.js'), + { + defaultConfig: path.join( + __dirname, + 'integration/custom-configs/.parcelrc-svg-react', + ), + }, + ); + + let file = await outputFS.readFile(b.getBundles()[0].filePath, 'utf-8'); + assert(!file.includes('inkscape')); + assert(file.includes('function SvgIcon')); + assert(file.includes('_react.createElement("svg"')); + }); +}); diff --git a/packages/core/integration-tests/test/svg.js b/packages/core/integration-tests/test/svg.js index 58a84542584..302a26a1f9c 100644 --- a/packages/core/integration-tests/test/svg.js +++ b/packages/core/integration-tests/test/svg.js @@ -1,10 +1,101 @@ import assert from 'assert'; -import {bundle, outputFS} from '@parcel/test-utils'; +import {assertBundles, bundle, distDir, outputFS} from '@parcel/test-utils'; import path from 'path'; describe('svg', function() { + it('should support bundling SVG', async () => { + let b = await bundle(path.join(__dirname, '/integration/svg/circle.svg')); + + assertBundles(b, [ + { + name: 'circle.svg', + assets: ['circle.svg'], + }, + { + name: 'other1.html', + assets: ['other1.html'], + }, + { + type: 'svg', + assets: ['square.svg'], + }, + { + name: 'other2.html', + assets: ['other2.html'], + }, + { + type: 'svg', + assets: ['path.svg'], + }, + { + type: 'svg', + assets: ['gradient.svg'], + }, + { + type: 'js', + assets: ['script.js'], + }, + { + type: 'js', + assets: ['module.js', 'script.js'], + }, + { + type: 'css', + assets: ['style.css'], + }, + ]); + + let file = await outputFS.readFile( + b.getBundles().find(b => b.type === 'svg').filePath, + 'utf-8', + ); + assert(file.includes('')); + assert(file.includes('`, + ), + ); + }); + it('should minify SVG bundles', async function() { - let b = await bundle(path.join(__dirname, '/integration/svg/index.html'), { + let b = await bundle(path.join(__dirname, '/integration/svg/circle.svg'), { defaultTargetOptions: { shouldOptimize: true, }, @@ -14,7 +105,7 @@ describe('svg', function() { b.getBundles().find(b => b.type === 'svg').filePath, 'utf-8', ); - assert(!file.includes('inkscape')); + assert(!file.includes('comment')); }); it('support SVGO config files', async function() { @@ -35,17 +126,120 @@ describe('svg', function() { assert(file.includes('comment')); }); - it('should support transforming SVGs to react components', async function() { - let b = await bundle(path.join(__dirname, '/integration/svg/react.js'), { - defaultConfig: path.join( - __dirname, - 'integration/custom-configs/.parcelrc-svg', + it('should detect xml-stylesheet processing instructions', async function() { + let b = await bundle( + path.join(__dirname, '/integration/svg-xml-stylesheet/img.svg'), + ); + + assertBundles(b, [ + { + name: 'img.svg', + assets: ['img.svg'], + }, + { + type: 'css', + assets: ['style1.css'], + }, + { + type: 'css', + assets: ['style3.css'], + }, + ]); + + let file = await outputFS.readFile( + b.getBundles().find(b => b.type === 'svg').filePath, + 'utf-8', + ); + + assert(file.includes(' b.name.startsWith('gradient')).filePath, + )}#myGradient)"`, ), - }); + ); + assert(svg.includes('