From 8442c623c084e3a1b2e545ba19bf6f532bc71fdb Mon Sep 17 00:00:00 2001 From: Kid <44045911+kidonng@users.noreply.github.com> Date: Fri, 11 Mar 2022 12:41:31 +0800 Subject: [PATCH 01/19] Improve emoji support detection (#7775) Co-authored-by: Agnieszka Gawrys --- packages/reporters/cli/src/emoji.js | 20 ++++++++++++++++++-- packages/utils/create-react-app/src/emoji.js | 20 ++++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/packages/reporters/cli/src/emoji.js b/packages/reporters/cli/src/emoji.js index aa3a16190ba..6b05521ce52 100644 --- a/packages/reporters/cli/src/emoji.js +++ b/packages/reporters/cli/src/emoji.js @@ -1,7 +1,23 @@ // @flow strict-local -const supportsEmoji = - process.platform !== 'win32' || process.env.TERM === 'xterm-256color'; +// From https://github.com/sindresorhus/is-unicode-supported/blob/8f123916d5c25a87c4f966dcc248b7ca5df2b4ca/index.js +// This package is ESM-only so it has to be vendored +function isUnicodeSupported() { + if (process.platform !== 'win32') { + return process.env.TERM !== 'linux'; // Linux console (kernel) + } + + return ( + Boolean(process.env.CI) || + Boolean(process.env.WT_SESSION) || // Windows Terminal + process.env.ConEmuTask === '{cmd::Cmder}' || // ConEmu and cmder + process.env.TERM_PROGRAM === 'vscode' || + process.env.TERM === 'xterm-256color' || + process.env.TERM === 'alacritty' + ); +} + +const supportsEmoji = isUnicodeSupported(); // Fallback symbols for Windows from https://en.wikipedia.org/wiki/Code_page_437 export const progress: string = supportsEmoji ? '⏳' : '∞'; diff --git a/packages/utils/create-react-app/src/emoji.js b/packages/utils/create-react-app/src/emoji.js index d40d6dd0dfd..a9e581d68ab 100644 --- a/packages/utils/create-react-app/src/emoji.js +++ b/packages/utils/create-react-app/src/emoji.js @@ -1,7 +1,23 @@ // @flow strict-local -const supportsEmoji = - process.platform !== 'win32' || process.env.TERM === 'xterm-256color'; +// From https://github.com/sindresorhus/is-unicode-supported/blob/8f123916d5c25a87c4f966dcc248b7ca5df2b4ca/index.js +// This package is ESM-only so it has to be vendored +function isUnicodeSupported() { + if (process.platform !== 'win32') { + return process.env.TERM !== 'linux'; // Linux console (kernel) + } + + return ( + Boolean(process.env.CI) || + Boolean(process.env.WT_SESSION) || // Windows Terminal + process.env.ConEmuTask === '{cmd::Cmder}' || // ConEmu and cmder + process.env.TERM_PROGRAM === 'vscode' || + process.env.TERM === 'xterm-256color' || + process.env.TERM === 'alacritty' + ); +} + +const supportsEmoji = isUnicodeSupported(); // Fallback symbols for Windows from https://en.wikipedia.org/wiki/Code_page_437 export const progress: string = supportsEmoji ? '⏳' : '∞'; From ef16fad82001dd112c4dd46d79dce47968bb10b8 Mon Sep 17 00:00:00 2001 From: solstice23 Date: Fri, 11 Mar 2022 12:48:12 +0800 Subject: [PATCH 02/19] Human readable file size in bundle analyzer report (#7766) --- packages/reporters/bundle-analyzer/client/index.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/reporters/bundle-analyzer/client/index.js b/packages/reporters/bundle-analyzer/client/index.js index 59d87017ce4..f31ea232525 100644 --- a/packages/reporters/bundle-analyzer/client/index.js +++ b/packages/reporters/bundle-analyzer/client/index.js @@ -53,7 +53,7 @@ let foamtree = new CarrotSearchFoamTree({
Size
-
${e.group.weight} bytes
+
${formatSize(e.group.weight)}
@@ -100,3 +100,12 @@ function debounce(fn, delay) { function translate3d(x, y, z) { return `translate3d(${x}px, ${y}px, ${z}px)`; } + +const UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; +function formatSize(x) { + let l = 0, n = parseInt(x, 10) || 0; + while(n >= 1000 && ++l){ + n /= 1000; + } + return(`${n.toFixed(l > 0 ? 2 : 0)} ${UNITS[l]}`); +} From e294eafd9a49c056fb4b223c5ace5c0653428ede Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Sat, 12 Mar 2022 20:27:22 +0100 Subject: [PATCH 03/19] Bump swc (#7777) --- Cargo.lock | 699 ++++++++++++------ .../core/integration-tests/test/javascript.js | 3 +- packages/transformers/js/core/Cargo.toml | 4 +- .../js/core/src/dependency_collector.rs | 374 +++++----- .../transformers/js/core/src/env_replacer.rs | 32 +- packages/transformers/js/core/src/fs.rs | 57 +- .../js/core/src/global_replacer.rs | 26 +- packages/transformers/js/core/src/hoist.rs | 475 ++++++------ packages/transformers/js/core/src/lib.rs | 7 +- packages/transformers/js/core/src/modules.rs | 64 +- packages/transformers/js/core/src/utils.rs | 80 +- packages/transformers/js/package.json | 2 +- yarn.lock | 8 +- 13 files changed, 987 insertions(+), 844 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15b049bdb7e..52fd9b59c82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,7 +30,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.3", + "getrandom 0.2.5", "once_cell", "serde", "version_check", @@ -56,9 +56,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.52" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3" +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" [[package]] name = "arrayvec" @@ -66,11 +66,17 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + [[package]] name = "ast_node" -version = "0.7.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96d5444b02f3080edac8a144f6baf29b2fb6ff589ad4311559731a7c7529381" +checksum = "bc4c00309ed1c8104732df4a5fa9acc3b796b6f8531dfbd5ce0078c86f997244" dependencies = [ "darling", "pmutil", @@ -93,9 +99,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" @@ -109,6 +115,15 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "better_scoped_tls" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73e8ecdec39e98aa3b19e8cd0b8ed8f77ccb86a6b0b2dc7cd86d105438a2123" +dependencies = [ + "scoped-tls", +] + [[package]] name = "bit-vec" version = "0.6.3" @@ -130,11 +145,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + [[package]] name = "browserslist-rs" -version = "0.6.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31071741816efb54c473a6480724b2d31ed44eb460382d37f60cf4655fbe80a6" +checksum = "a0f43be8e0fc9203f6ed7731d2a9a6bf5924cb78907e67e1fe9133617be402be" dependencies = [ "ahash", "anyhow", @@ -162,15 +186,15 @@ checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" [[package]] name = "bumpalo" -version = "3.8.0" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "bytemuck" -version = "1.7.3" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" +checksum = "0e851ca7c24871e7336801608a4797d7376545b6928a10d32d75685687141ead" [[package]] name = "byteorder" @@ -180,9 +204,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.72" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" dependencies = [ "jobserver", ] @@ -297,18 +321,18 @@ checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" [[package]] name = "crc32fast" -version = "1.3.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "crossbeam-channel" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -327,9 +351,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.5" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -340,14 +364,24 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" dependencies = [ "cfg-if 1.0.0", "lazy_static", ] +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "darling" version = "0.10.2" @@ -393,6 +427,17 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "dashmap" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0834a35a3fce649144119e18da2a4d8ed12ef3862f47183fd46f625d072d96c" +dependencies = [ + "cfg-if 1.0.0", + "num_cpus", + "parking_lot 0.12.0", +] + [[package]] name = "data-encoding" version = "2.3.2" @@ -427,6 +472,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", +] + [[package]] name = "dunce" version = "1.0.2" @@ -459,7 +514,7 @@ checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.2.10", + "redox_syscall 0.2.11", "winapi", ] @@ -499,9 +554,9 @@ checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" [[package]] name = "generic-array" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" dependencies = [ "typenum", "version_check", @@ -520,9 +575,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" dependencies = [ "cfg-if 1.0.0", "libc", @@ -590,9 +645,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg", "hashbrown", @@ -601,9 +656,9 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a75aeaaef0ce18b58056d306c27b07436fbb34b8816c53094b76dd81803136" +checksum = "e7906a9fababaeacb774f72410e497a1d18de916322e33797bb2cd29baa23c9e" dependencies = [ "unindent", ] @@ -619,9 +674,9 @@ dependencies = [ [[package]] name = "is-macro" -version = "0.1.9" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a322dd16d960e322c3d92f541b4c1a4f0a2e81e1fdeee430d8cecc8b72e8015f" +checksum = "94b2c46692aee0d1b3aad44e781ac0f0e7db42ef27adaa0a877b627040019813" dependencies = [ "Inflector", "pmutil", @@ -692,65 +747,115 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lexical" -version = "5.2.2" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f404a90a744e32e8be729034fc33b90cf2a56418fbf594d69aa3c0214ad414e5" +checksum = "ccd3e434c16f0164124ade12dcdee324fcc3dafb1cad0c7f1d8c2451a1aa6886" dependencies = [ - "cfg-if 1.0.0", "lexical-core", ] [[package]] name = "lexical-core" -version = "0.7.6" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +checksum = "92912c4af2e7d9075be3e5e3122c4d7263855fa6cce34fbece4dd08e5884624d" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f518eed87c3be6debe6d26b855c97358d8a11bf05acec137e5f53080f5ad2dd8" +dependencies = [ + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-parse-integer" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc852ec67c6538bbb2b9911116a385b24510e879a69ab516e6a151b15a79168" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c72a9d52c5c4e62fa2cdc2cb6c694a39ae1382d9c2a17a466f18e272a0930eb1" dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 1.0.0", - "ryu", + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26f6202bff3d35ede41a6200227837468bb92e4ecdd437328b1055ed218fb855" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "094060bd2a7c2ff3a16d5304a6ae82727cb3cc9d1c70f813cc73f744c319337e" +dependencies = [ + "lexical-util", "static_assertions", ] [[package]] name = "libc" -version = "0.2.112" +version = "0.2.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" [[package]] name = "libdeflate-sys" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ce0b849741cecad96125e51124570c46741f50db12007224295b63e221f0034" +checksum = "4cceaf6e335d658ec0602685bfe50d0f35248d6d8848b194058bfda37a9eb728" dependencies = [ "cc", ] [[package]] name = "libdeflater" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b32b70f071880dd130e410be35f8017892837913374a311e277219d3ead3ab18" +checksum = "15f0c115fd181333eb7a82cf42e2ce2d9fac0ad06babd3ab79a9ec5bd66352fe" dependencies = [ "libdeflate-sys", ] [[package]] name = "libmimalloc-sys" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9636c194f9db483f4d0adf2f99a65011a99f904bd222bbd67fb4df4f37863c30" +checksum = "7705fc40f6ed493f73584abbb324e74f96b358ff60dfe5659a0f8fc12c590a69" dependencies = [ "cc", ] [[package]] name = "lock_api" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" dependencies = [ "scopeguard", ] @@ -787,9 +892,9 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5f78c1d9892fb5677a8b2f543f967ab891ac0f71feecd961435b74f877283a" +checksum = "b0dfa131390c2f6bdb3242f65ff271fcdaca5ff7b6c08f28398be7f2280e3926" dependencies = [ "libmimalloc-sys", ] @@ -867,9 +972,9 @@ checksum = "67cf20e0081fea04e044aa4adf74cfea8ddc0324eec2894b1c700f4cafc72a56" [[package]] name = "nasm-rs" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06380d23b58dcdaf892fa36c3950cad3110e7d76851275d5f85c22eb9cdd614" +checksum = "ce095842aee9aa3ecbda7a5d2a4df680375fd128a8596b6b56f8e497e231f483" dependencies = [ "rayon", ] @@ -902,9 +1007,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.2.6" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" dependencies = [ "autocfg", "num-integer", @@ -965,9 +1070,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] name = "opaque-debug" @@ -977,22 +1082,13 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "ordered-float" -version = "2.8.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97c9d06878b3a851e8026ef94bf7fef9ba93062cd412601da4d9cf369b1cc62d" +checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" dependencies = [ "num-traits", ] -[[package]] -name = "owning_ref" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" -dependencies = [ - "stable_deref_trait", -] - [[package]] name = "oxipng" version = "5.0.1" @@ -1063,7 +1159,7 @@ dependencies = [ "pathdiff", "serde", "serde_bytes", - "sha-1", + "sha-1 0.9.8", "swc_atoms", "swc_common", "swc_ecmascript", @@ -1087,7 +1183,7 @@ version = "0.1.0" dependencies = [ "js-sys", "parcel-js-swc-core", - "parking_lot_core", + "parking_lot_core 0.8.0", "serde", "serde-wasm-bindgen", "wasm-bindgen", @@ -1101,7 +1197,17 @@ checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" dependencies = [ "instant", "lock_api", - "parking_lot_core", + "parking_lot_core 0.8.0", +] + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.1", ] [[package]] @@ -1119,6 +1225,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "parking_lot_core" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.11", + "smallvec", + "windows-sys", +] + [[package]] name = "path-clean" version = "0.1.0" @@ -1145,12 +1264,12 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "phf" -version = "0.8.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" dependencies = [ "phf_macros", - "phf_shared", + "phf_shared 0.10.0", "proc-macro-hack", ] @@ -1160,18 +1279,28 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" dependencies = [ - "phf_shared", - "rand", + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.5", ] [[package]] name = "phf_macros" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.10.0", + "phf_shared 0.10.0", "proc-macro-hack", "proc-macro2", "quote", @@ -1187,11 +1316,20 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" [[package]] name = "pmutil" @@ -1218,9 +1356,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "precomputed-hash" @@ -1228,6 +1366,23 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "preset_env_base" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e44b8d534a4ecea4519138ff80780a499691c4e948bc063651487e069966a703" +dependencies = [ + "ahash", + "anyhow", + "browserslist-rs", + "dashmap 4.0.2", + "from_variant", + "once_cell", + "semver 1.0.6", + "serde", + "st-map", +] + [[package]] name = "proc-macro-hack" version = "0.5.19" @@ -1245,9 +1400,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" dependencies = [ "proc-macro2", ] @@ -1260,12 +1415,23 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ "getrandom 0.1.16", "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.2.2", + "rand_core 0.5.1", "rand_hc", "rand_pcg", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.3", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -1273,7 +1439,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.3", ] [[package]] @@ -1285,13 +1461,22 @@ dependencies = [ "getrandom 0.1.16", ] +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.5", +] + [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core", + "rand_core 0.5.1", ] [[package]] @@ -1300,7 +1485,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" dependencies = [ - "rand_core", + "rand_core 0.5.1", ] [[package]] @@ -1336,18 +1521,18 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", @@ -1360,17 +1545,11 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" -[[package]] -name = "retain_mut" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11000e6ba5020e53e7cc26f73b91ae7d5496b4977851479edb66b694c0675c21" - [[package]] name = "rgb" -version = "0.8.31" +version = "0.8.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a374af9a0e5fdcdd98c1c7b64f05004f9ea2555b6c75f211daa81268a3c50f1" +checksum = "e74fdc210d8f24a7dbfedc13b04ba5764f5232754ccebfdf5fff1bad791ccbc6" dependencies = [ "bytemuck", ] @@ -1396,7 +1575,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.4", + "semver 1.0.6", ] [[package]] @@ -1405,15 +1584,6 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "scoped-tls" version = "1.0.0" @@ -1433,14 +1603,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ "semver-parser", - "serde", ] [[package]] name = "semver" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" +checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d" +dependencies = [ + "serde", +] [[package]] name = "semver-parser" @@ -1450,9 +1622,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.132" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" dependencies = [ "serde_derive", ] @@ -1480,9 +1652,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.132" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", @@ -1491,9 +1663,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.73" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" dependencies = [ "itoa", "ryu", @@ -1506,24 +1678,35 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.9.0", "opaque-debug", ] +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.3", +] + [[package]] name = "siphasher" -version = "0.3.7" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "smallvec" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "sourcemap" @@ -1547,16 +1730,10 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3caeb13a58f859600a7b75fffe66322e1fca0122ca02cfc7262344a7e30502d1" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "static-map-macro", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "static-map-macro" version = "0.2.1" @@ -1590,14 +1767,14 @@ dependencies = [ [[package]] name = "string_cache" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923f0f39b6267d37d23ce71ae7235602134b250ace715dd2c90421998ddac0c6" +checksum = "33994d0838dc2d152d17a62adf608a869b5e846b65b389af7f3dbc1de45c5b26" dependencies = [ "lazy_static", "new_debug_unreachable", - "parking_lot", - "phf_shared", + "parking_lot 0.11.1", + "phf_shared 0.10.0", "precomputed-hash", "serde", ] @@ -1608,8 +1785,8 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.8.0", + "phf_shared 0.8.0", "proc-macro2", "quote", ] @@ -1649,25 +1826,40 @@ dependencies = [ "string_cache_codegen", ] +[[package]] +name = "swc_cached" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84fed4a980e12c737171a7b17c5e0a2f4272899266fa0632ea4e31264ebdfdb5" +dependencies = [ + "ahash", + "anyhow", + "dashmap 5.1.0", + "once_cell", + "regex", + "serde", + "swc_atoms", +] + [[package]] name = "swc_common" -version = "0.15.1" +version = "0.17.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf33ac965b9ce43b653baa35a5de6ecfd96b9bbab9547a5fb4ce33c46a36fe75" +checksum = "af06472bfc423fb7b75c483eccfb9b6790db9de0fb2d6ff1ef8369a2551a3707" dependencies = [ "ahash", "ast_node", "atty", - "cfg-if 0.1.10", + "better_scoped_tls", + "cfg-if 1.0.0", "debug_unreachable", "either", "from_variant", "num-bigint", "once_cell", - "owning_ref", "rustc-hash", - "scoped-tls", "serde", + "siphasher", "sourcemap", "string_cache", "swc_eq_ignore_macros", @@ -1680,9 +1872,9 @@ dependencies = [ [[package]] name = "swc_ecma_ast" -version = "0.60.3" +version = "0.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ab2356281c38cf629f3cdb165c4d34e17b2757b020dab914bae477ee0fb373" +checksum = "e35d736b61d3dceb5a4e18a86d69bfc352aa7136fd3c5a6c2f3353231cd9d839" dependencies = [ "is-macro", "num-bigint", @@ -1690,14 +1882,14 @@ dependencies = [ "string_enum", "swc_atoms", "swc_common", - "unicode-xid", + "unicode-id", ] [[package]] name = "swc_ecma_codegen" -version = "0.84.1" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "383ac26d122a9f97a1773ffa6f44366e8ab08ccc14e5698111c698ca17acfa65" +checksum = "8fa4a2b82e2bab5bea6472e23b14bd96c462ae9e1e29d9af2ea8ea6d58dcc406" dependencies = [ "bitflags", "memchr", @@ -1708,7 +1900,6 @@ dependencies = [ "swc_common", "swc_ecma_ast", "swc_ecma_codegen_macros", - "swc_ecma_parser", "tracing", ] @@ -1727,28 +1918,27 @@ dependencies = [ [[package]] name = "swc_ecma_loader" -version = "0.25.4" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645b674e9f537053026670985486004a47c3c168a71de8de0c0d57c2f2cb61f8" +checksum = "f9ab69df5d4de425833e02de111f14b5544b39ad9c9b82c97e4835fc55c8f1b6" dependencies = [ "ahash", "anyhow", - "dashmap", + "dashmap 4.0.2", "normpath", "once_cell", "path-clean", "serde", "serde_json", - "swc_atoms", "swc_common", "tracing", ] [[package]] name = "swc_ecma_parser" -version = "0.82.6" +version = "0.93.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b0455e02c59d53891422593b2e0aaf06548873a1c319ddcf3e9a741d34ce41d" +checksum = "6bcc4ebfd0c5f7c9e5fd03b3dff680d61e997e51147e6f4738ee3274be5ad382" dependencies = [ "either", "enum_kind", @@ -1761,22 +1951,22 @@ dependencies = [ "swc_ecma_ast", "tracing", "typed-arena 2.0.1", - "unicode-xid", + "unicode-id", ] [[package]] name = "swc_ecma_preset_env" -version = "0.76.2" +version = "0.106.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4ce83d144d995a8362cea85fe7c6adaa728fbe4a8bad05d05f8d3d2b27e37b" +checksum = "4c76924d65625afb0536c433d59a6f63fee0388e0ab7f121bda9ec92a84b4678" dependencies = [ "ahash", "anyhow", - "browserslist-rs", - "dashmap", + "dashmap 5.1.0", "indexmap", "once_cell", - "semver 0.9.0", + "preset_env_base", + "semver 1.0.6", "serde", "serde_json", "st-map", @@ -1787,19 +1977,17 @@ dependencies = [ "swc_ecma_transforms", "swc_ecma_utils", "swc_ecma_visit", - "walkdir", ] [[package]] name = "swc_ecma_transforms" -version = "0.103.8" +version = "0.131.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e5d7bbc83aca7b172f18fe1ad713a58490f7420bd4831481e18a3d86e0199f" +checksum = "484ab8024a62c8f35a408898d0b8aa664e03a992c2f262cda6173274f48d955e" dependencies = [ "swc_atoms", "swc_common", "swc_ecma_ast", - "swc_ecma_parser", "swc_ecma_transforms_base", "swc_ecma_transforms_compat", "swc_ecma_transforms_module", @@ -1809,18 +1997,18 @@ dependencies = [ "swc_ecma_transforms_typescript", "swc_ecma_utils", "swc_ecma_visit", - "unicode-xid", ] [[package]] name = "swc_ecma_transforms_base" -version = "0.49.2" +version = "0.67.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f401256219e566fc92f637182d20eb04de8cd1bb650dd72d3e0e81851a5367b" +checksum = "6786157670709b3c9e2a81aee7aef8042b582b4b599f233025b28ca5353a29d9" dependencies = [ + "better_scoped_tls", "once_cell", "phf", - "scoped-tls", + "serde", "smallvec", "swc_atoms", "swc_common", @@ -1833,9 +2021,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_classes" -version = "0.36.1" +version = "0.55.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd400da7c4b061a95c38f98d7a72f12c7cf7d49fee33e5bb5ca577e19a344b52" +checksum = "6dd06b4fa72cd85640fcab59c210c34c8e63f6ea5e547c856febcf18000c0bda" dependencies = [ "swc_atoms", "swc_common", @@ -1847,12 +2035,12 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_compat" -version = "0.59.10" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d76ac375527f495b5b095e7e32d43e47b57113abe72b75306dcd58b4d15fbde" +checksum = "f622788e39755b4a0b9902e37314fbc59f163d5e9e24c121a95c8352fb00e1e0" dependencies = [ "ahash", - "arrayvec", + "arrayvec 0.7.2", "indexmap", "is-macro", "num-bigint", @@ -1867,6 +2055,7 @@ dependencies = [ "swc_ecma_transforms_macros", "swc_ecma_utils", "swc_ecma_visit", + "swc_trace_macro", "tracing", ] @@ -1885,9 +2074,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_module" -version = "0.65.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "701c941a6ba8d4e396a3e63031a9d4ee4807dc91b29c30069e88c0276a44a01e" +checksum = "3b050435473be3392bdc665682cf3637c006ea5fe57f6f58cf3be08ae597fab9" dependencies = [ "Inflector", "ahash", @@ -1896,6 +2085,7 @@ dependencies = [ "pathdiff", "serde", "swc_atoms", + "swc_cached", "swc_common", "swc_ecma_ast", "swc_ecma_loader", @@ -1903,19 +2093,19 @@ dependencies = [ "swc_ecma_transforms_base", "swc_ecma_utils", "swc_ecma_visit", + "tracing", ] [[package]] name = "swc_ecma_transforms_optimization" -version = "0.73.1" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37dddf3630b5c60aa4d05e3486099eec7195d96ec17895fa58753d383935b09c" +checksum = "a0638979a3445e49125ab28a30dc734c272e66406db5583d9095f459543056ac" dependencies = [ "ahash", - "dashmap", + "dashmap 5.1.0", "indexmap", "once_cell", - "retain_mut", "serde_json", "swc_atoms", "swc_common", @@ -1930,9 +2120,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_proposal" -version = "0.65.2" +version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1493c6460a5009cff53e5adaac7e2090bde73be9dccb92b01fe132c190824b2" +checksum = "7bf987316b088789266b108b9ad87f8479402a76233565ef31807103766bc079" dependencies = [ "either", "serde", @@ -1940,7 +2130,6 @@ dependencies = [ "swc_atoms", "swc_common", "swc_ecma_ast", - "swc_ecma_parser", "swc_ecma_transforms_base", "swc_ecma_transforms_classes", "swc_ecma_transforms_macros", @@ -1950,18 +2139,18 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_react" -version = "0.67.1" +version = "0.93.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12a9c3ed9ff2c30faba6851d9287a2b21a9efdc0f4aba234980f8c57028bf2ea" +checksum = "dd2d009bb8be4149a1b3bb8ea2e4c59c5a26ed5b5ae797563026887480ed9141" dependencies = [ "ahash", "base64 0.13.0", - "dashmap", + "dashmap 5.1.0", "indexmap", "once_cell", "regex", "serde", - "sha-1", + "sha-1 0.10.0", "string_enum", "swc_atoms", "swc_common", @@ -1975,15 +2164,14 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_typescript" -version = "0.69.1" +version = "0.96.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00d48c902c53d5118ecfa5eb8346d78a9d51f062da425bf03bfc101205b390f6" +checksum = "ed2e388f0b424de694aac45aaad513e7ccb03aeb87ed42781ce353e1346b3d86" dependencies = [ "serde", "swc_atoms", "swc_common", "swc_ecma_ast", - "swc_ecma_parser", "swc_ecma_transforms_base", "swc_ecma_transforms_react", "swc_ecma_utils", @@ -1992,24 +2180,24 @@ dependencies = [ [[package]] name = "swc_ecma_utils" -version = "0.56.2" +version = "0.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a3cb85935a25f5a78bdcf8252a0423eeb3aa3d027c16d2ae425454e0ab2a4c2" +checksum = "43689c9f051b48c4ea9eb86b236b27277594a9c4311d3ee88d7007f5d65b1ff5" dependencies = [ + "indexmap", "once_cell", "swc_atoms", "swc_common", "swc_ecma_ast", "swc_ecma_visit", "tracing", - "unicode-xid", ] [[package]] name = "swc_ecma_visit" -version = "0.46.0" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c03856f785763e50019ebd70281e9490c5b019f93cfc1dda180d49e30fcb4c" +checksum = "9b70316301b54ead435ae2660824ba3049de1854710b73395e1b8e615dc0bca6" dependencies = [ "num-bigint", "swc_atoms", @@ -2021,9 +2209,9 @@ dependencies = [ [[package]] name = "swc_ecmascript" -version = "0.99.9" +version = "0.132.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f0c9a2b6acfa0fff19ba80a6bff86240417bd9b1a168af97c3591eea99555" +checksum = "7fa1f0e2b8bcb94f30b276c633743e6d2cf06e5ceb0561fe1bb55d47d020921e" dependencies = [ "swc_ecma_ast", "swc_ecma_codegen", @@ -2058,6 +2246,17 @@ dependencies = [ "syn", ] +[[package]] +name = "swc_trace_macro" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d1a05fdb40442d687cb2eff4e5c374886a66ced1436ad87515de7d72b3ec10b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "swc_visit" version = "0.3.0" @@ -2070,9 +2269,9 @@ dependencies = [ [[package]] name = "swc_visit_macros" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e505bbf8e11898fa05a65aa5e773c827ec743fc15aa3c064c9e06164ed0b6630" +checksum = "c3b9b72892df873972549838bf84d6c56234c7502148a7e23b5a3da6e0fedfb8" dependencies = [ "Inflector", "pmutil", @@ -2095,9 +2294,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" dependencies = [ "winapi-util", ] @@ -2167,9 +2366,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", @@ -2179,9 +2378,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.18" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" +checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" dependencies = [ "proc-macro2", "quote", @@ -2190,9 +2389,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c" dependencies = [ "lazy_static", ] @@ -2221,6 +2420,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +[[package]] +name = "unicode-id" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4285d92be83dfbc8950a2601178b89ed36f979ebf51bfcf7b272b17001184e6c" + [[package]] name = "unicode-normalization" version = "0.1.19" @@ -2244,9 +2449,9 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "unindent" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" +checksum = "514672a55d7380da379785a4d70ca8386c8883ff7eaae877be4d2081cebe73d8" [[package]] name = "unreachable" @@ -2277,9 +2482,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "void" @@ -2287,17 +2492,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -2406,11 +2600,54 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" + +[[package]] +name = "windows_i686_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" + +[[package]] +name = "windows_i686_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" + [[package]] name = "xxhash-rust" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575e15bedf6e57b5c2d763ffc6c3c760143466cbd09d762d539680ab5992ded" +checksum = "886f21441c6731b9e06a9fdacbc5e29319c17a4069c2a511d80349874864702d" [[package]] name = "zopfli" diff --git a/packages/core/integration-tests/test/javascript.js b/packages/core/integration-tests/test/javascript.js index dda211e5016..f58347ca760 100644 --- a/packages/core/integration-tests/test/javascript.js +++ b/packages/core/integration-tests/test/javascript.js @@ -23,6 +23,7 @@ import {makeDeferredWithPromise, normalizePath} from '@parcel/utils'; import vm from 'vm'; import Logger from '@parcel/logger'; import nullthrows from 'nullthrows'; +import {md} from '@parcel/diagnostic'; describe('javascript', function () { beforeEach(async () => { @@ -5308,7 +5309,7 @@ describe('javascript', function () { name: 'BuildError', diagnostics: [ { - message: `Failed to resolve '@swc/helpers' from '${normalizePath( + message: md`Failed to resolve '@swc/helpers' from '${normalizePath( require.resolve('@parcel/transformer-js/src/JSTransformer.js'), )}'`, origin: '@parcel/core', diff --git a/packages/transformers/js/core/Cargo.toml b/packages/transformers/js/core/Cargo.toml index ea54f194fe4..250ed2ecf78 100644 --- a/packages/transformers/js/core/Cargo.toml +++ b/packages/transformers/js/core/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" crate-type = ["rlib"] [dependencies] -swc_ecmascript = { version = "0.99.9", features = ["parser", "transforms", "module", "optimization", "react", "typescript", "utils", "visit", "codegen", "utils", "preset_env"] } -swc_common = { version = "0.15.1", features = ["tty-emitter", "sourcemap"] } +swc_ecmascript = { version = "0.132.0", features = ["parser", "transforms", "module", "optimization", "react", "typescript", "utils", "visit", "codegen", "utils", "preset_env"] } +swc_common = { version = "0.17.15", features = ["tty-emitter", "sourcemap"] } swc_atoms = "0.2.9" indoc = "1.0.3" serde = "1.0.123" diff --git a/packages/transformers/js/core/src/dependency_collector.rs b/packages/transformers/js/core/src/dependency_collector.rs index 0113d96838d..1da4b632c90 100644 --- a/packages/transformers/js/core/src/dependency_collector.rs +++ b/packages/transformers/js/core/src/dependency_collector.rs @@ -6,7 +6,7 @@ use std::path::Path; use serde::{Deserialize, Serialize}; use swc_atoms::JsWord; use swc_common::{Mark, SourceMap, Span, SyntaxContext, DUMMY_SP}; -use swc_ecmascript::ast; +use swc_ecmascript::ast::{self, Callee, MemberProp}; use swc_ecmascript::utils::ident::IdentLike; use swc_ecmascript::visit::{Fold, FoldWith}; @@ -185,7 +185,7 @@ impl<'a> DependencyCollector<'a> { // For scripts, we replace with __parcel__require__, which is later replaced // by a real parcelRequire of the resolved asset in the packager. if self.config.source_type == SourceType::Script { - res.callee = ast::ExprOrSuper::Expr(Box::new(ast::Expr::Ident(ast::Ident::new( + res.callee = ast::Callee::Expr(Box::new(ast::Expr::Ident(ast::Ident::new( "__parcel__require__".into(), DUMMY_SP, )))); @@ -326,166 +326,164 @@ impl<'a> Fold for DependencyCollector<'a> { } fn fold_call_expr(&mut self, node: ast::CallExpr) -> ast::CallExpr { - use ast::{Expr::*, ExprOrSuper::*, Ident}; + use ast::{Expr::*, Ident}; - let call_expr = match node.callee.clone() { - Super(_) => return node, - Expr(boxed) => boxed, - }; - - let kind = match &*call_expr { - Ident(ident) => { - // Bail if defined in scope - if self.decls.contains(&ident.to_id()) { - return node.fold_children_with(self); - } - - match ident.sym.to_string().as_str() { - "import" => DependencyKind::DynamicImport, - "require" => { - if self.in_promise { - DependencyKind::DynamicImport - } else { - DependencyKind::Require + let kind = match &node.callee { + Callee::Import(_) => DependencyKind::DynamicImport, + Callee::Expr(expr) => { + match &**expr { + Ident(ident) => { + // Bail if defined in scope + if self.decls.contains(&ident.to_id()) { + return node.fold_children_with(self); } - } - "importScripts" => { - if self.config.is_worker { - let (msg, span) = if self.config.source_type == SourceType::Script { - // Ignore if argument is not a string literal. - let span = if let Some(ast::ExprOrSpread { expr, .. }) = node.args.get(0) { - match &**expr { - Lit(ast::Lit::Str(ast::Str { value, span, .. })) => { - // Ignore absolute URLs. - if value.starts_with("http:") - || value.starts_with("https:") - || value.starts_with("//") - { - return node.fold_children_with(self); + + match ident.sym.to_string().as_str() { + "require" => { + if self.in_promise { + DependencyKind::DynamicImport + } else { + DependencyKind::Require + } + } + "importScripts" => { + if self.config.is_worker { + let (msg, span) = if self.config.source_type == SourceType::Script { + // Ignore if argument is not a string literal. + let span = if let Some(ast::ExprOrSpread { expr, .. }) = node.args.get(0) { + match &**expr { + Lit(ast::Lit::Str(ast::Str { value, span, .. })) => { + // Ignore absolute URLs. + if value.starts_with("http:") + || value.starts_with("https:") + || value.starts_with("//") + { + return node.fold_children_with(self); + } + span + } + _ => { + return node.fold_children_with(self); + } } - span - } - _ => { + } else { return node.fold_children_with(self); - } - } - } else { - return node.fold_children_with(self); - }; - - ( - "Argument to importScripts() must be a fully qualified URL.", - *span, - ) - } else { - ( - "importScripts() is not supported in module workers.", - node.span, - ) - }; - self.diagnostics.push(Diagnostic { - message: msg.to_string(), - code_highlights: Some(vec![CodeHighlight { - message: None, - loc: SourceLocation::from(self.source_map, span), - }]), - hints: Some(vec![String::from( - "Use a static `import`, or dynamic `import()` instead.", - )]), - show_environment: self.config.source_type == SourceType::Script, - severity: DiagnosticSeverity::Error, - documentation_url: Some(String::from( - "https://parceljs.org/languages/javascript/#classic-script-workers", - )), - }); - } + }; + + ( + "Argument to importScripts() must be a fully qualified URL.", + *span, + ) + } else { + ( + "importScripts() is not supported in module workers.", + node.span, + ) + }; + self.diagnostics.push(Diagnostic { + message: msg.to_string(), + code_highlights: Some(vec![CodeHighlight { + message: None, + loc: SourceLocation::from(self.source_map, span), + }]), + hints: Some(vec![String::from( + "Use a static `import`, or dynamic `import()` instead.", + )]), + show_environment: self.config.source_type == SourceType::Script, + severity: DiagnosticSeverity::Error, + documentation_url: Some(String::from( + "https://parceljs.org/languages/javascript/#classic-script-workers", + )), + }); + } - return node.fold_children_with(self); - } - "__parcel__require__" => { - let mut call = node.fold_children_with(self); - call.callee = ast::ExprOrSuper::Expr(Box::new(ast::Expr::Ident(ast::Ident::new( - "require".into(), - DUMMY_SP.apply_mark(self.ignore_mark), - )))); - return call; - } - "__parcel__import__" => { - let mut call = node.fold_children_with(self); - call.callee = ast::ExprOrSuper::Expr(Box::new(ast::Expr::Ident(ast::Ident::new( - "import".into(), - DUMMY_SP.apply_mark(self.ignore_mark), - )))); - return call; - } - "__parcel__importScripts__" => { - let mut call = node.fold_children_with(self); - call.callee = ast::ExprOrSuper::Expr(Box::new(ast::Expr::Ident(ast::Ident::new( - "importScripts".into(), - DUMMY_SP.apply_mark(self.ignore_mark), - )))); - return call; - } - _ => return node.fold_children_with(self), - } - } - Member(member) => { - if match_member_expr(member, vec!["module", "require"], self.decls) { - DependencyKind::Require - } else if self.config.is_browser - && match_member_expr( - member, - vec!["navigator", "serviceWorker", "register"], - self.decls, - ) - { - DependencyKind::ServiceWorker - } else if self.config.is_browser - && match_member_expr(member, vec!["CSS", "paintWorklet", "addModule"], self.decls) - { - DependencyKind::Worklet - } else { - let was_in_promise = self.in_promise; - - // Match compiled dynamic imports (Parcel) - // Promise.resolve(require('foo')) - if match_member_expr(member, vec!["Promise", "resolve"], self.decls) { - if let Some(expr) = node.args.get(0) { - if match_require(&*expr.expr, self.decls, Mark::fresh(Mark::root())).is_some() { - self.in_promise = true; - let node = node.fold_children_with(self); - self.in_promise = was_in_promise; - return node; + return node.fold_children_with(self); + } + "__parcel__require__" => { + let mut call = node.fold_children_with(self); + call.callee = ast::Callee::Expr(Box::new(ast::Expr::Ident(ast::Ident::new( + "require".into(), + DUMMY_SP.apply_mark(self.ignore_mark), + )))); + return call; + } + "__parcel__import__" => { + let mut call = node.fold_children_with(self); + call.callee = ast::Callee::Expr(Box::new(ast::Expr::Ident(ast::Ident::new( + "import".into(), + DUMMY_SP.apply_mark(self.ignore_mark), + )))); + return call; + } + "__parcel__importScripts__" => { + let mut call = node.fold_children_with(self); + call.callee = ast::Callee::Expr(Box::new(ast::Expr::Ident(ast::Ident::new( + "importScripts".into(), + DUMMY_SP.apply_mark(self.ignore_mark), + )))); + return call; } + _ => return node.fold_children_with(self), } } + Member(member) => { + if match_member_expr(member, vec!["module", "require"], self.decls) { + DependencyKind::Require + } else if self.config.is_browser + && match_member_expr( + member, + vec!["navigator", "serviceWorker", "register"], + self.decls, + ) + { + DependencyKind::ServiceWorker + } else if self.config.is_browser + && match_member_expr(member, vec!["CSS", "paintWorklet", "addModule"], self.decls) + { + DependencyKind::Worklet + } else { + let was_in_promise = self.in_promise; + + // Match compiled dynamic imports (Parcel) + // Promise.resolve(require('foo')) + if match_member_expr(member, vec!["Promise", "resolve"], self.decls) { + if let Some(expr) = node.args.get(0) { + if match_require(&*expr.expr, self.decls, Mark::fresh(Mark::root())).is_some() { + self.in_promise = true; + let node = node.fold_children_with(self); + self.in_promise = was_in_promise; + return node; + } + } + } - // Match compiled dynamic imports (TypeScript) - // Promise.resolve().then(() => require('foo')) - // Promise.resolve().then(() => { return require('foo') }) - // Promise.resolve().then(function () { return require('foo') }) - if let Expr(ref expr) = member.obj { - if let Call(call) = &**expr { - if let Expr(e) = &call.callee { - if let Member(m) = &**e { - if match_member_expr(m, vec!["Promise", "resolve"], self.decls) { - if let Ident(id) = &*member.prop { - if id.sym.to_string().as_str() == "then" { - if let Some(arg) = node.args.get(0) { - match &*arg.expr { - Fn(_) | Arrow(_) => { - self.in_promise = true; - let node = swc_ecmascript::visit::fold_call_expr(self, node.clone()); - self.in_promise = was_in_promise; - - // Transform Promise.resolve().then(() => __importStar(require('foo'))) - // => Promise.resolve().then(() => require('foo')).then(res => __importStar(res)) - if let Some(require_node) = self.require_node.clone() { - self.require_node = None; - return build_promise_chain(node, require_node); + // Match compiled dynamic imports (TypeScript) + // Promise.resolve().then(() => require('foo')) + // Promise.resolve().then(() => { return require('foo') }) + // Promise.resolve().then(function () { return require('foo') }) + if let Call(call) = &*member.obj { + if let Callee::Expr(e) = &call.callee { + if let Member(m) = &**e { + if match_member_expr(m, vec!["Promise", "resolve"], self.decls) { + if let MemberProp::Ident(id) = &member.prop { + if id.sym.to_string().as_str() == "then" { + if let Some(arg) = node.args.get(0) { + match &*arg.expr { + Fn(_) | Arrow(_) => { + self.in_promise = true; + let node = + swc_ecmascript::visit::fold_call_expr(self, node.clone()); + self.in_promise = was_in_promise; + + // Transform Promise.resolve().then(() => __importStar(require('foo'))) + // => Promise.resolve().then(() => require('foo')).then(res => __importStar(res)) + if let Some(require_node) = self.require_node.clone() { + self.require_node = None; + return build_promise_chain(node, require_node); + } } + _ => {} } - _ => {} } } } @@ -493,10 +491,11 @@ impl<'a> Fold for DependencyCollector<'a> { } } } + + return node.fold_children_with(self); } } - - return node.fold_children_with(self); + _ => return node.fold_children_with(self), } } _ => return node.fold_children_with(self), @@ -637,7 +636,7 @@ impl<'a> Fold for DependencyCollector<'a> { SourceType::Module => "require", SourceType::Script => "__parcel__require__", }; - call.callee = ast::ExprOrSuper::Expr(Box::new(ast::Expr::Ident(ast::Ident::new( + call.callee = ast::Callee::Expr(Box::new(ast::Expr::Ident(ast::Ident::new( name.into(), DUMMY_SP, )))); @@ -824,10 +823,7 @@ impl<'a> Fold for DependencyCollector<'a> { // Free `require` -> undefined sym == &js_word!("require") && !self.decls.contains(&(sym.clone(), span.ctxt())) } - Expr::Member(MemberExpr { - obj: ExprOrSuper::Expr(expr), - .. - }) => { + Expr::Member(MemberExpr { obj: expr, .. }) => { // e.g. `require.extensions` -> undefined if let Expr::Ident(Ident { sym, span, .. }) = &**expr { sym == &js_word!("require") && !self.decls.contains(&(sym.clone(), span.ctxt())) @@ -884,7 +880,7 @@ impl<'a> DependencyCollector<'a> { }; if let Some(ast::Expr::Call(call)) = expr { - if let ast::ExprOrSuper::Expr(callee) = &call.callee { + if let ast::Callee::Expr(callee) = &call.callee { if let ast::Expr::Ident(id) = &**callee { if id.to_id() == resolve_id { if let Some(arg) = call.args.get(0) { @@ -969,10 +965,9 @@ fn build_promise_chain(node: ast::CallExpr, require_node: ast::CallExpr) -> ast: }; return ast::CallExpr { - callee: ast::ExprOrSuper::Expr(Box::new(ast::Expr::Member(ast::MemberExpr { + callee: ast::Callee::Expr(Box::new(ast::Expr::Member(ast::MemberExpr { span: DUMMY_SP, - computed: false, - obj: ast::ExprOrSuper::Expr(Box::new(ast::Expr::Call(ast::CallExpr { + obj: (Box::new(ast::Expr::Call(ast::CallExpr { callee: node.callee, args: vec![ast::ExprOrSpread { expr: Box::new(ast::Expr::Fn(ast::FnExpr { @@ -999,7 +994,7 @@ fn build_promise_chain(node: ast::CallExpr, require_node: ast::CallExpr) -> ast: span: DUMMY_SP, type_args: None, }))), - prop: Box::new(ast::Expr::Ident(ast::Ident::new("then".into(), DUMMY_SP))), + prop: MemberProp::Ident(ast::Ident::new("then".into(), DUMMY_SP)), }))), args: vec![ast::ExprOrSpread { expr: Box::new(f), @@ -1020,12 +1015,11 @@ fn create_url_constructor(url: ast::Expr, use_import_meta: bool) -> ast::Expr { let expr = if use_import_meta { Expr::Member(MemberExpr { span: DUMMY_SP, - obj: ExprOrSuper::Expr(Box::new(Expr::MetaProp(MetaPropExpr { - meta: Ident::new(js_word!("import"), DUMMY_SP), - prop: Ident::new(js_word!("meta"), DUMMY_SP), - }))), - prop: Box::new(Expr::Ident(Ident::new(js_word!("url"), DUMMY_SP))), - computed: false, + obj: Box::new(Expr::MetaProp(MetaPropExpr { + kind: MetaPropKind::ImportMeta, + span: DUMMY_SP, + })), + prop: MemberProp::Ident(Ident::new(js_word!("url"), DUMMY_SP)), }) } else { // CJS output: "file:" + __filename @@ -1162,16 +1156,11 @@ impl<'a> DependencyCollector<'a> { match expr { Expr::Member(member) => { - match &member.obj { - ExprOrSuper::Expr(expr) if self.is_import_meta(&**expr) => {} - _ => return false, + if !self.is_import_meta(&member.obj) { + return false; } - let name = if !member.computed { - match_str_or_ident(&*member.prop) - } else { - match_str(&*member.prop) - }; + let name = match_property_name(member); if let Some((name, _)) = name { name == js_word!("url") @@ -1203,15 +1192,8 @@ impl<'a> DependencyCollector<'a> { match &expr { ast::Expr::MetaProp(MetaPropExpr { - meta: Ident { - sym: js_word!("import"), - .. - }, - prop: Ident { - sym: js_word!("meta"), - span, - .. - }, + kind: MetaPropKind::ImportMeta, + span, }) => { if self.config.source_type == SourceType::Script { self.diagnostics.push(Diagnostic { @@ -1279,25 +1261,17 @@ impl<'a> DependencyCollector<'a> { decls: vec![VarDeclarator { name: Pat::Ident(BindingIdent::from(ident.clone())), init: Some(Box::new(Expr::Call(CallExpr { - callee: ExprOrSuper::Expr(Box::new(Expr::Member(MemberExpr { - obj: ExprOrSuper::Expr(Box::new(Expr::Ident(Ident::new( - js_word!("Object"), - DUMMY_SP, - )))), - prop: Box::new(Expr::Ident(Ident::new("assign".into(), DUMMY_SP))), - computed: false, + callee: Callee::Expr(Box::new(Expr::Member(MemberExpr { + obj: Box::new(Expr::Ident(Ident::new(js_word!("Object"), DUMMY_SP))), + prop: MemberProp::Ident(Ident::new("assign".into(), DUMMY_SP)), span: DUMMY_SP, }))), args: vec![ ExprOrSpread { expr: Box::new(Expr::Call(CallExpr { - callee: ExprOrSuper::Expr(Box::new(Expr::Member(MemberExpr { - obj: ExprOrSuper::Expr(Box::new(Expr::Ident(Ident::new( - js_word!("Object"), - DUMMY_SP, - )))), - prop: Box::new(Expr::Ident(Ident::new("create".into(), DUMMY_SP))), - computed: false, + callee: Callee::Expr(Box::new(Expr::Member(MemberExpr { + obj: (Box::new(Expr::Ident(Ident::new(js_word!("Object"), DUMMY_SP)))), + prop: MemberProp::Ident(Ident::new("create".into(), DUMMY_SP)), span: DUMMY_SP, }))), args: vec![ExprOrSpread { diff --git a/packages/transformers/js/core/src/env_replacer.rs b/packages/transformers/js/core/src/env_replacer.rs index b72db0ae312..46b52f4c093 100644 --- a/packages/transformers/js/core/src/env_replacer.rs +++ b/packages/transformers/js/core/src/env_replacer.rs @@ -53,25 +53,11 @@ impl<'a> Fold for EnvReplacer<'a> { return node.fold_children_with(self); } - if let MemberExpr { - obj: ExprOrSuper::Expr(ref expr), - ref prop, - computed, - .. - } = member - { - if let Expr::Member(member) = &**expr { - if match_member_expr(member, vec!["process", "env"], self.decls) { - if let Expr::Lit(Lit::Str(Str { value: ref sym, .. })) = &**prop { - if let Some(replacement) = self.replace(sym, true) { - return replacement; - } - } else if let Expr::Ident(Ident { ref sym, .. }) = &**prop { - if !computed { - if let Some(replacement) = self.replace(sym, true) { - return replacement; - } - } + if let Expr::Member(obj) = &*member.obj { + if match_member_expr(obj, vec!["process", "env"], self.decls) { + if let Some((sym, _)) = match_property_name(member) { + if let Some(replacement) = self.replace(&sym, true) { + return replacement; } } } @@ -128,11 +114,7 @@ impl<'a> Fold for EnvReplacer<'a> { PatOrExpr::Expr(expr) => Some(&**expr), }; - if let Some(Expr::Member(MemberExpr { - obj: ExprOrSuper::Expr(ref obj), - .. - })) = expr - { + if let Some(Expr::Member(MemberExpr { obj, .. })) = &expr { if let Expr::Member(member) = &**obj { if match_member_expr(member, vec!["process", "env"], self.decls) { self.emit_mutating_error(assign.span); @@ -148,7 +130,7 @@ impl<'a> Fold for EnvReplacer<'a> { Expr::Unary(UnaryExpr { op: UnaryOp::Delete, arg, span, .. }) | // e.g. process.env.UPDATE++ Expr::Update(UpdateExpr { arg, span, .. }) => { - if let Expr::Member(MemberExpr { obj: ExprOrSuper::Expr(ref obj), .. }) = &**arg { + if let Expr::Member(MemberExpr { ref obj, .. }) = &**arg { if let Expr::Member(member) = &**obj { if match_member_expr(member, vec!["process", "env"], self.decls) { self.emit_mutating_error(*span); diff --git a/packages/transformers/js/core/src/fs.rs b/packages/transformers/js/core/src/fs.rs index 2bdca62c70e..291e156ebfd 100644 --- a/packages/transformers/js/core/src/fs.rs +++ b/packages/transformers/js/core/src/fs.rs @@ -1,21 +1,15 @@ use crate::dependency_collector::{DependencyDescriptor, DependencyKind}; use crate::hoist::{Collect, Import}; -use crate::utils::SourceLocation; +use crate::id; +use crate::utils::{IdentId, SourceLocation}; use data_encoding::{BASE64, HEXLOWER}; use std::collections::HashSet; use std::path::{Path, PathBuf}; use swc_atoms::JsWord; -use swc_common::{Mark, Span, SyntaxContext, DUMMY_SP}; +use swc_common::{Mark, Span, DUMMY_SP}; use swc_ecmascript::ast::*; use swc_ecmascript::visit::{Fold, FoldWith, VisitWith}; -type IdentId = (JsWord, SyntaxContext); -macro_rules! id { - ($ident: expr) => { - ($ident.sym.clone(), $ident.span.ctxt) - }; -} - pub fn inline_fs<'a>( filename: &str, source_map: swc_common::sync::Lrc, @@ -55,7 +49,7 @@ impl<'a> Fold for InlineFS<'a> { fn fold_expr(&mut self, node: Expr) -> Expr { if let Expr::Call(call) = &node { - if let ExprOrSuper::Expr(expr) = &call.callee { + if let Callee::Expr(expr) = &call.callee { if let Some((source, specifier)) = self.match_module_reference(expr) { if &source == "fs" && &specifier == "readFileSync" { if let Some(arg) = call.args.get(0) { @@ -84,31 +78,29 @@ impl<'a> InlineFS<'a> { } } Expr::Member(member) => { - let prop = match &*member.prop { - Expr::Ident(ident) => { - if !member.computed { - ident.sym.clone() + let prop = match &member.prop { + MemberProp::Ident(ident) => ident.sym.clone(), + MemberProp::Computed(ComputedPropName { expr, .. }) => { + if let Expr::Lit(Lit::Str(str_)) = &**expr { + str_.value.clone() } else { return None; } } - Expr::Lit(Lit::Str(str_)) => str_.value.clone(), _ => return None, }; - if let ExprOrSuper::Expr(expr) = &member.obj { - if let Some(source) = self.collect.match_require(expr) { - return Some((source, prop)); - } + if let Some(source) = self.collect.match_require(&*member.obj) { + return Some((source, prop)); + } - if let Expr::Ident(ident) = &**expr { - if let Some(Import { - source, specifier, .. - }) = self.collect.imports.get(&id!(ident)) - { - if specifier == "default" || specifier == "*" { - return Some((source.clone(), prop)); - } + if let Expr::Ident(ident) = &*member.obj { + if let Some(Import { + source, specifier, .. + }) = self.collect.imports.get(&id!(ident)) + { + if specifier == "default" || specifier == "*" { + return Some((source.clone(), prop)); } } } @@ -196,13 +188,12 @@ impl<'a> InlineFS<'a> { // If buffer, wrap in Buffer.from(base64String, 'base64') if encoding == "buffer" { Some(Expr::Call(CallExpr { - callee: ExprOrSuper::Expr(Box::new(Expr::Member(MemberExpr { - obj: ExprOrSuper::Expr(Box::new(Expr::Ident(Ident::new( + callee: Callee::Expr(Box::new(Expr::Member(MemberExpr { + obj: Box::new(Expr::Ident(Ident::new( "Buffer".into(), DUMMY_SP.apply_mark(self.global_mark), - )))), - prop: Box::new(Expr::Ident(Ident::new("from".into(), DUMMY_SP))), - computed: false, + ))), + prop: MemberProp::Ident(Ident::new("from".into(), DUMMY_SP)), span: DUMMY_SP, }))), args: vec![ @@ -286,7 +277,7 @@ impl<'a> Fold for Evaluator<'a> { }, Expr::Call(call) => { let callee = match &call.callee { - ExprOrSuper::Expr(expr) => &*expr, + Callee::Expr(expr) => &*expr, _ => return node, }; diff --git a/packages/transformers/js/core/src/global_replacer.rs b/packages/transformers/js/core/src/global_replacer.rs index 9332dd3e839..512d5eeaa2f 100644 --- a/packages/transformers/js/core/src/global_replacer.rs +++ b/packages/transformers/js/core/src/global_replacer.rs @@ -4,7 +4,7 @@ use std::path::Path; use swc_atoms::JsWord; use swc_common::{SourceMap, SyntaxContext, DUMMY_SP}; -use swc_ecmascript::ast; +use swc_ecmascript::ast::{self, ComputedPropName}; use swc_ecmascript::utils::ident::IdentLike; use swc_ecmascript::visit::{Fold, FoldWith}; @@ -24,12 +24,12 @@ pub struct GlobalReplacer<'a> { impl<'a> Fold for GlobalReplacer<'a> { fn fold_expr(&mut self, node: ast::Expr) -> ast::Expr { - use ast::{Expr::*, Ident, MemberExpr}; + use ast::{Expr::*, Ident, MemberExpr, MemberProp}; // Do not traverse into the `prop` side of member expressions unless computed. let node = match node { Member(expr) => { - if expr.computed { + if let MemberProp::Computed(_) = expr.prop { Member(MemberExpr { obj: expr.obj.fold_with(self), prop: expr.prop.fold_with(self), @@ -87,9 +87,8 @@ impl<'a> Fold for GlobalReplacer<'a> { id.sym.clone(), self.global_mark, Member(MemberExpr { - obj: ast::ExprOrSuper::Expr(Box::new(Call(create_require(specifier.clone())))), - prop: Box::new(Ident(ast::Ident::new("Buffer".into(), DUMMY_SP))), - computed: false, + obj: Box::new(Call(create_require(specifier.clone()))), + prop: MemberProp::Ident(ast::Ident::new("Buffer".into(), DUMMY_SP)), span: DUMMY_SP, }), ), @@ -169,15 +168,14 @@ impl<'a> Fold for GlobalReplacer<'a> { id.sym.clone(), self.global_mark, ast::Expr::Member(ast::MemberExpr { - obj: ast::ExprOrSuper::Expr(Box::new(Ident(Ident::new( - js_word!("arguments"), - DUMMY_SP, - )))), - prop: Box::new(Lit(ast::Lit::Num(ast::Number { - value: 3.0, + obj: Box::new(Ident(Ident::new(js_word!("arguments"), DUMMY_SP))), + prop: MemberProp::Computed(ComputedPropName { span: DUMMY_SP, - }))), - computed: true, + expr: Box::new(Lit(ast::Lit::Num(ast::Number { + value: 3.0, + span: DUMMY_SP, + }))), + }), span: DUMMY_SP, }), ), diff --git a/packages/transformers/js/core/src/hoist.rs b/packages/transformers/js/core/src/hoist.rs index 02e17bce0b1..f4c71995c17 100644 --- a/packages/transformers/js/core/src/hoist.rs +++ b/packages/transformers/js/core/src/hoist.rs @@ -1,4 +1,4 @@ -use crate::utils::match_property_name; +use crate::utils::{match_export_name, match_export_name_ident, match_property_name}; use serde::{Deserialize, Serialize}; use std::collections::hash_map::DefaultHasher; use std::collections::{HashMap, HashSet}; @@ -206,13 +206,13 @@ impl<'a> Fold for Hoist<'a> { match specifier { ExportSpecifier::Named(named) => { let exported = match named.exported { - Some(exported) => exported.sym, - None => named.orig.sym.clone(), + Some(exported) => match_export_name(&exported).0, + None => match_export_name(&named.orig).0.clone(), }; self.re_exports.push(ImportedSymbol { source: src.value.clone(), local: exported, - imported: named.orig.sym, + imported: match_export_name(&named.orig).0, loc: SourceLocation::from(&self.collect.source_map, named.span), }); } @@ -227,7 +227,7 @@ impl<'a> Fold for Hoist<'a> { ExportSpecifier::Namespace(namespace) => { self.re_exports.push(ImportedSymbol { source: src.value.clone(), - local: namespace.name.sym, + local: match_export_name(&namespace.name).0, imported: "*".into(), loc: SourceLocation::from(&self.collect.source_map, namespace.span), }); @@ -237,10 +237,10 @@ impl<'a> Fold for Hoist<'a> { } else { for specifier in export.specifiers { if let ExportSpecifier::Named(named) = specifier { - let id = id!(named.orig); + let id = id!(match_export_name_ident(&named.orig)); let exported = match named.exported { - Some(exported) => exported.sym, - None => named.orig.sym, + Some(exported) => match_export_name(&exported).0, + None => match_export_name(&named.orig).0, }; if let Some(Import { source, specifier, .. @@ -406,46 +406,44 @@ impl<'a> Fold for Hoist<'a> { } if let Expr::Member(member) = &**init { - if let ExprOrSuper::Expr(expr) = &member.obj { - // Match var x = require('foo').bar; - if let Some(source) = - match_require(&*expr, &self.collect.decls, self.collect.ignore_mark) - { - if !self.collect.non_static_requires.contains(&source) { - // If this is not the first declarator in the variable declaration, we need to - // split the declaration into multiple to preserve side effect ordering. - // var x = sideEffect(), y = require('foo').bar, z = 2; - // -> var x = sideEffect(); import 'foo'; var y = $id$import$foo$bar, z = 2; - if !decls.is_empty() { - let var = VarDecl { - span: var.span, - kind: var.kind, - declare: var.declare, - decls: std::mem::take(&mut decls), - }; - self - .module_items - .push(ModuleItem::Stmt(Stmt::Decl(Decl::Var(var)))); - } - + // Match var x = require('foo').bar; + if let Some(source) = + match_require(&*member.obj, &self.collect.decls, self.collect.ignore_mark) + { + if !self.collect.non_static_requires.contains(&source) { + // If this is not the first declarator in the variable declaration, we need to + // split the declaration into multiple to preserve side effect ordering. + // var x = sideEffect(), y = require('foo').bar, z = 2; + // -> var x = sideEffect(); import 'foo'; var y = $id$import$foo$bar, z = 2; + if !decls.is_empty() { + let var = VarDecl { + span: var.span, + kind: var.kind, + declare: var.declare, + decls: std::mem::take(&mut decls), + }; self .module_items - .push(ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl { - specifiers: vec![], - asserts: None, - span: DUMMY_SP, - src: Str { - value: format!("{}:{}", self.module_id, source).into(), - span: DUMMY_SP, - kind: StrKind::Synthesized, - has_escape: false, - }, - type_only: false, - }))); - - self.handle_non_const_require(v, &source); - continue; + .push(ModuleItem::Stmt(Stmt::Decl(Decl::Var(var)))); } + + self + .module_items + .push(ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl { + specifiers: vec![], + asserts: None, + span: DUMMY_SP, + src: Str { + value: format!("{}:{}", self.module_id, source).into(), + span: DUMMY_SP, + kind: StrKind::Synthesized, + has_escape: false, + }, + type_only: false, + }))); + + self.handle_non_const_require(v, &source); + continue; } } } @@ -541,110 +539,101 @@ impl<'a> Fold for Hoist<'a> { } } - let key = match &*member.prop { - Expr::Ident(ident) => { - if !member.computed { - ident.sym.clone() - } else { - return Expr::Member(member.fold_children_with(self)); - } - } - Expr::Lit(Lit::Str(str_)) => str_.value.clone(), + let key = match match_property_name(&member) { + Some(v) => v.0, _ => return Expr::Member(member.fold_children_with(self)), }; - if let ExprOrSuper::Expr(ref expr) = member.obj { - match &**expr { - Expr::Ident(ident) => { - // import * as y from 'x'; OR const y = require('x'); OR const y = await import('x'); - // y.foo -> $id$import$d141bba7fdc215a3$y - if let Some(Import { - source, - specifier, - kind, - .. - }) = self.collect.imports.get(&id!(ident)) + match &*member.obj { + Expr::Ident(ident) => { + // import * as y from 'x'; OR const y = require('x'); OR const y = await import('x'); + // y.foo -> $id$import$d141bba7fdc215a3$y + if let Some(Import { + source, + specifier, + kind, + .. + }) = self.collect.imports.get(&id!(ident)) + { + // If there are any non-static accesses of the namespace, don't perform any replacement. + // This will be handled in the Ident visitor below, which replaces y -> $id$import$d141bba7fdc215a3. + if specifier == "*" + && !self.collect.non_static_access.contains_key(&id!(ident)) + && !self.collect.non_const_bindings.contains_key(&id!(ident)) + && !self.collect.non_static_requires.contains(source) { - // If there are any non-static accesses of the namespace, don't perform any replacement. - // This will be handled in the Ident visitor below, which replaces y -> $id$import$d141bba7fdc215a3. - if specifier == "*" - && !self.collect.non_static_access.contains_key(&id!(ident)) - && !self.collect.non_const_bindings.contains_key(&id!(ident)) - && !self.collect.non_static_requires.contains(source) - { - if *kind == ImportKind::DynamicImport { - let name: JsWord = format!( - "${}$importAsync${:x}${:x}", - self.module_id, - hash!(source), - hash!(key) - ) - .into(); - self.imported_symbols.push(ImportedSymbol { - source: source.clone(), - local: name, - imported: key.clone(), - loc: SourceLocation::from(&self.collect.source_map, member.span), - }); - } else { - return Expr::Ident(self.get_import_ident( - member.span, - source, - &key, - SourceLocation::from(&self.collect.source_map, member.span), - )); - } + if *kind == ImportKind::DynamicImport { + let name: JsWord = format!( + "${}$importAsync${:x}${:x}", + self.module_id, + hash!(source), + hash!(key) + ) + .into(); + self.imported_symbols.push(ImportedSymbol { + source: source.clone(), + local: name, + imported: key.clone(), + loc: SourceLocation::from(&self.collect.source_map, member.span), + }); + } else { + return Expr::Ident(self.get_import_ident( + member.span, + source, + &key, + SourceLocation::from(&self.collect.source_map, member.span), + )); } } + } - // exports.foo -> $id$export$foo - let exports: JsWord = "exports".into(); - if ident.sym == exports - && !self.collect.decls.contains(&id!(ident)) - && self.collect.static_cjs_exports - && !self.collect.should_wrap - { - self.self_references.insert(key.clone()); - return Expr::Ident(self.get_export_ident(member.span, &key)); - } + // exports.foo -> $id$export$foo + let exports: JsWord = "exports".into(); + if ident.sym == exports + && !self.collect.decls.contains(&id!(ident)) + && self.collect.static_cjs_exports + && !self.collect.should_wrap + { + self.self_references.insert(key.clone()); + return Expr::Ident(self.get_export_ident(member.span, &key)); } - Expr::Call(_call) => { - // require('foo').bar -> $id$import$foo$bar - if let Some(source) = - match_require(expr, &self.collect.decls, self.collect.ignore_mark) - { - self.add_require(&source); - return Expr::Ident(self.get_import_ident( - member.span, - &source, - &key, - SourceLocation::from(&self.collect.source_map, member.span), - )); - } + } + Expr::Call(_call) => { + // require('foo').bar -> $id$import$foo$bar + if let Some(source) = + match_require(&member.obj, &self.collect.decls, self.collect.ignore_mark) + { + self.add_require(&source); + return Expr::Ident(self.get_import_ident( + member.span, + &source, + &key, + SourceLocation::from(&self.collect.source_map, member.span), + )); } - Expr::Member(mem) => { - // module.exports.foo -> $id$export$foo - if self.collect.static_cjs_exports - && !self.collect.should_wrap - && match_member_expr(mem, vec!["module", "exports"], &self.collect.decls) - { - self.self_references.insert(key.clone()); - return Expr::Ident(self.get_export_ident(member.span, &key)); - } + } + Expr::Member(mem) => { + // module.exports.foo -> $id$export$foo + if self.collect.static_cjs_exports + && !self.collect.should_wrap + && match_member_expr(mem, vec!["module", "exports"], &self.collect.decls) + { + self.self_references.insert(key.clone()); + return Expr::Ident(self.get_export_ident(member.span, &key)); } - Expr::This(_) => { - // this.foo -> $id$export$foo - if self.collect.static_cjs_exports - && !self.collect.should_wrap - && !self.in_function_scope - && !self.collect.is_esm - { - self.self_references.insert(key.clone()); - return Expr::Ident(self.get_export_ident(member.span, &key)); - } + } + Expr::This(_) => { + // this.foo -> $id$export$foo + if self.collect.static_cjs_exports + && !self.collect.should_wrap + && !self.in_function_scope + && !self.collect.is_esm + { + self.self_references.insert(key.clone()); + return Expr::Ident(self.get_export_ident(member.span, &key)); } - _ => {} } + _ => {} } // Don't visit member.prop so we avoid the ident visitor. @@ -652,7 +641,6 @@ impl<'a> Fold for Hoist<'a> { span: member.span, obj: member.obj.fold_with(self), prop: member.prop, - computed: member.computed, }); } Expr::Call(ref call) => { @@ -845,17 +833,14 @@ impl<'a> Fold for Hoist<'a> { }; } - let is_cjs_exports = match &member.obj { - ExprOrSuper::Expr(expr) => match &**expr { - Expr::Member(member) => { - match_member_expr(member, vec!["module", "exports"], &self.collect.decls) - } - Expr::Ident(ident) => { - let exports: JsWord = "exports".into(); - ident.sym == exports && !self.collect.decls.contains(&id!(ident)) - } - _ => false, - }, + let is_cjs_exports = match &*member.obj { + Expr::Member(member) => { + match_member_expr(member, vec!["module", "exports"], &self.collect.decls) + } + Expr::Ident(ident) => { + let exports: JsWord = "exports".into(); + ident.sym == exports && !self.collect.decls.contains(&id!(ident)) + } _ => false, }; @@ -898,9 +883,8 @@ impl<'a> Fold for Hoist<'a> { } else { PatOrExpr::Pat(Box::new(Pat::Expr(Box::new(Expr::Member(MemberExpr { span: member.span, - obj: ExprOrSuper::Expr(Box::new(Expr::Ident(ident.id))), + obj: Box::new(Expr::Ident(ident.id)), prop: member.prop.clone().fold_with(self), - computed: member.computed, }))))) }, right: node.right.fold_with(self), @@ -1337,7 +1321,7 @@ impl Visit for Collect { match specifier { ImportSpecifier::Named(named) => { let imported = match &named.imported { - Some(imported) => imported.sym.clone(), + Some(imported) => match_export_name(imported).0.clone(), None => named.local.sym.clone(), }; self.imports.insert( @@ -1382,22 +1366,22 @@ impl Visit for Collect { match specifier { ExportSpecifier::Named(named) => { let exported = match &named.exported { - Some(exported) => exported.clone(), - None => named.orig.clone(), + Some(exported) => match_export_name(exported), + None => match_export_name(&named.orig), }; self.exports.insert( - exported.sym.clone(), + exported.0.clone(), Export { - specifier: named.orig.sym.clone(), - loc: SourceLocation::from(&self.source_map, exported.span), + specifier: match_export_name_ident(&named.orig).sym.clone(), + loc: SourceLocation::from(&self.source_map, exported.1), source, }, ); if node.src.is_none() { self .exports_locals - .entry(named.orig.sym.clone()) - .or_insert_with(|| exported.sym.clone()); + .entry(match_export_name_ident(&named.orig).sym.clone()) + .or_insert_with(|| exported.0.clone()); } } ExportSpecifier::Default(default) => { @@ -1418,7 +1402,7 @@ impl Visit for Collect { } ExportSpecifier::Namespace(namespace) => { self.exports.insert( - namespace.name.sym.clone(), + match_export_name(&namespace.name).0, Export { specifier: "*".into(), loc: SourceLocation::from(&self.source_map, namespace.span), @@ -1654,45 +1638,43 @@ impl Visit for Collect { }; } - if let ExprOrSuper::Expr(expr) = &node.obj { - match &**expr { - Expr::Member(member) => { - if match_member_expr(member, vec!["module", "exports"], &self.decls) { - handle_export!(); - } - return; + match &*node.obj { + Expr::Member(member) => { + if match_member_expr(member, vec!["module", "exports"], &self.decls) { + handle_export!(); + } + return; + } + Expr::Ident(ident) => { + let exports: JsWord = "exports".into(); + if ident.sym == exports && !self.decls.contains(&id!(ident)) { + handle_export!(); } - Expr::Ident(ident) => { - let exports: JsWord = "exports".into(); - if ident.sym == exports && !self.decls.contains(&id!(ident)) { - handle_export!(); - } - if ident.sym == js_word!("module") && !self.decls.contains(&id!(ident)) { - self.has_cjs_exports = true; - self.static_cjs_exports = false; - self.should_wrap = true; - self.add_bailout(node.span, BailoutReason::FreeModule); - } + if ident.sym == js_word!("module") && !self.decls.contains(&id!(ident)) { + self.has_cjs_exports = true; + self.static_cjs_exports = false; + self.should_wrap = true; + self.add_bailout(node.span, BailoutReason::FreeModule); + } - // `import` isn't really an identifier... - if match_property_name(node).is_none() && ident.sym != js_word!("import") { - self - .non_static_access - .entry(id!(ident)) - .or_default() - .push(node.span); - } - return; + // `import` isn't really an identifier... + if match_property_name(node).is_none() && ident.sym != js_word!("import") { + self + .non_static_access + .entry(id!(ident)) + .or_default() + .push(node.span); } - Expr::This(_this) => { - if self.in_module_this { - handle_export!(); - } - return; + return; + } + Expr::This(_this) => { + if self.in_module_this { + handle_export!(); } - _ => {} + return; } + _ => {} } node.visit_children_with(self); @@ -1822,43 +1804,32 @@ impl Visit for Collect { match &**init { Expr::Member(member) => { - if let ExprOrSuper::Expr(expr) = &member.obj { - if let Some(source) = self.match_require(&*expr) { - // Convert member expression on require to a destructuring assignment. - // const yx = require('y').x; -> const {x: yx} = require('x'); - let key = match &*member.prop { - Expr::Ident(ident) => { - if !member.computed { - PropName::Ident(ident.clone()) - } else { - PropName::Computed(ComputedPropName { - span: DUMMY_SP, - expr: Box::new(*expr.clone()), - }) - } - } - Expr::Lit(Lit::Str(str_)) => PropName::Str(str_.clone()), - _ => PropName::Computed(ComputedPropName { - span: DUMMY_SP, - expr: Box::new(*expr.clone()), - }), - }; + if let Some(source) = self.match_require(&*member.obj) { + // Convert member expression on require to a destructuring assignment. + // const yx = require('y').x; -> const {x: yx} = require('x'); + let key = match &member.prop { + MemberProp::Computed(_) => PropName::Computed(ComputedPropName { + span: DUMMY_SP, + expr: Box::new(*member.obj.clone()), + }), + MemberProp::Ident(ident) => PropName::Ident(ident.clone()), + _ => unreachable!(), + }; - self.add_pat_imports( - &Pat::Object(ObjectPat { - optional: false, - span: DUMMY_SP, - type_ann: None, - props: vec![ObjectPatProp::KeyValue(KeyValuePatProp { - key, - value: Box::new(node.name.clone()), - })], - }), - &source, - ImportKind::Require, - ); - return; - } + self.add_pat_imports( + &Pat::Object(ObjectPat { + optional: false, + span: DUMMY_SP, + type_ann: None, + props: vec![ObjectPatProp::KeyValue(KeyValuePatProp { + key, + value: Box::new(node.name.clone()), + })], + }), + &source, + ImportKind::Require, + ); + return; } } Expr::Await(await_exp) => { @@ -1882,7 +1853,7 @@ impl Visit for Collect { } fn visit_call_expr(&mut self, node: &CallExpr) { - if let ExprOrSuper::Expr(expr) = &node.callee { + if let Callee::Expr(expr) = &node.callee { match &**expr { Expr::Ident(ident) => { if ident.sym == js_word!("eval") && !self.decls.contains(&id!(ident)) { @@ -1892,34 +1863,26 @@ impl Visit for Collect { } Expr::Member(member) => { // import('foo').then(foo => ...); - if let ExprOrSuper::Expr(obj) = &member.obj { - if let Some(source) = match_import(&*obj, self.ignore_mark) { - let then: JsWord = "then".into(); - let is_then = match &*member.prop { - Expr::Ident(ident) => !member.computed && ident.sym == then, - Expr::Lit(Lit::Str(str)) => str.value == then, - _ => false, - }; - - if is_then { - if let Some(ExprOrSpread { expr, .. }) = node.args.get(0) { - let param = match &**expr { - Expr::Fn(func) => func.function.params.get(0).map(|param| ¶m.pat), - Expr::Arrow(arrow) => arrow.params.get(0), - _ => None, - }; - - if let Some(param) = param { - self.add_pat_imports(param, &source, ImportKind::DynamicImport); - } else { - self.non_static_requires.insert(source.clone()); - self.wrapped_requires.insert(source); - self.add_bailout(node.span, BailoutReason::NonStaticDynamicImport); - } + if let Some(source) = match_import(&*member.obj, self.ignore_mark) { + let then: JsWord = "then".into(); + if match_property_name(member).map_or(false, |f| f.0 == then) { + if let Some(ExprOrSpread { expr, .. }) = node.args.get(0) { + let param = match &**expr { + Expr::Fn(func) => func.function.params.get(0).map(|param| ¶m.pat), + Expr::Arrow(arrow) => arrow.params.get(0), + _ => None, + }; - expr.visit_with(self); - return; + if let Some(param) = param { + self.add_pat_imports(param, &source, ImportKind::DynamicImport); + } else { + self.non_static_requires.insert(source.clone()); + self.wrapped_requires.insert(source); + self.add_bailout(node.span, BailoutReason::NonStaticDynamicImport); } + + expr.visit_with(self); + return; } } } diff --git a/packages/transformers/js/core/src/lib.rs b/packages/transformers/js/core/src/lib.rs index 3e9c161f629..4dcb6924e18 100644 --- a/packages/transformers/js/core/src/lib.rs +++ b/packages/transformers/js/core/src/lib.rs @@ -379,7 +379,12 @@ pub fn transform(config: Config) -> Result { ), // Transpile new syntax to older syntax if needed Optional::new( - preset_env(global_mark, Some(&comments), preset_env_config), + preset_env( + global_mark, + Some(&comments), + preset_env_config, + Default::default() + ), config.targets.is_some() ), // Inject SWC helpers if needed. diff --git a/packages/transformers/js/core/src/modules.rs b/packages/transformers/js/core/src/modules.rs index 7ef2ce3f43b..1a9567715fb 100644 --- a/packages/transformers/js/core/src/modules.rs +++ b/packages/transformers/js/core/src/modules.rs @@ -1,3 +1,5 @@ +use crate::id; +use crate::utils::{match_export_name, match_export_name_ident, IdentId}; use inflector::Inflector; use std::collections::{HashMap, HashSet}; use swc_atoms::JsWord; @@ -8,13 +10,6 @@ use swc_ecmascript::visit::{Fold, FoldWith}; use crate::fold_member_expr_skip_prop; -type IdentId = (JsWord, SyntaxContext); -macro_rules! id { - ($ident: expr) => { - ($ident.sym.clone(), $ident.span.ctxt) - }; -} - pub fn esm2cjs(node: Module, versions: Option) -> (Module, bool) { let mut fold = ESMFold { imports: HashMap::new(), @@ -138,10 +133,9 @@ impl ESMFold { self.needs_helpers = true; let ident = Ident::new("parcelHelpers".into(), DUMMY_SP.apply_mark(self.mark)); Expr::Call(CallExpr { - callee: ExprOrSuper::Expr(Box::new(Expr::Member(MemberExpr { - obj: ExprOrSuper::Expr(Box::new(Expr::Ident(ident))), - prop: Box::new(Expr::Ident(Ident::new(name, DUMMY_SP))), - computed: false, + callee: Callee::Expr(Box::new(Expr::Member(MemberExpr { + obj: Box::new(Expr::Ident(ident)), + prop: MemberProp::Ident(Ident::new(name, DUMMY_SP)), span: DUMMY_SP, }))), args: args @@ -218,12 +212,8 @@ impl ESMFold { expr: Box::new(Expr::Assign(AssignExpr { op: AssignOp::Assign, left: PatOrExpr::Expr(Box::new(Expr::Member(MemberExpr { - obj: ExprOrSuper::Expr(Box::new(Expr::Ident(Ident::new( - "exports".into(), - DUMMY_SP, - )))), - prop: Box::new(Expr::Ident(Ident::new(name, DUMMY_SP))), - computed: false, + obj: Box::new(Expr::Ident(Ident::new("exports".into(), DUMMY_SP))), + prop: MemberProp::Ident(Ident::new(name, DUMMY_SP)), span: DUMMY_SP, }))), right: Box::new(right), @@ -246,9 +236,8 @@ impl ESMFold { }; Expr::Member(MemberExpr { - obj: ExprOrSuper::Expr(Box::new(Expr::Ident(obj))), - prop: Box::new(Expr::Ident(Ident::new(imported.clone(), DUMMY_SP))), - computed: false, + obj: Box::new(Expr::Ident(obj)), + prop: MemberProp::Ident(Ident::new(imported.clone(), DUMMY_SP)), span, }) } @@ -281,7 +270,7 @@ impl Fold for ESMFold { match specifier { ImportSpecifier::Named(named) => { let imported = match &named.imported { - Some(imported) => imported.sym.clone(), + Some(imported) => match_export_name(imported).0.clone(), None => named.local.sym.clone(), }; self.imports.insert( @@ -340,13 +329,16 @@ impl Fold for ESMFold { None => named.orig.clone(), }; - if named.orig.sym == js_word!("default") { + if match_export_name(&named.orig).0 == js_word!("default") { self.create_interop_default(src.value.clone()); } - let specifier = - self.create_import_access(&src.value, &named.orig.sym, DUMMY_SP); - self.create_export(exported.sym, specifier, export.span); + let specifier = self.create_import_access( + &src.value, + &match_export_name(&named.orig).0, + DUMMY_SP, + ); + self.create_export(match_export_name(&exported).0, specifier, export.span); } ExportSpecifier::Default(default) => { self.create_interop_default(src.value.clone()); @@ -357,7 +349,7 @@ impl Fold for ESMFold { ExportSpecifier::Namespace(namespace) => { let local = self.get_require_name(&src.value, DUMMY_SP); self.create_export( - namespace.name.sym.clone(), + match_export_name(&namespace.name).0, Expr::Ident(local), export.span, ) @@ -371,17 +363,21 @@ impl Fold for ESMFold { Some(exported) => exported.clone(), None => named.orig.clone(), }; + let orig = match_export_name_ident(&named.orig); // Handle import {foo} from 'bar'; export {foo}; - let value = if let Some((source, imported)) = - self.imports.get(&id!(named.orig)).cloned() - { - self.create_import_access(&source, &imported, named.orig.span) - } else { - Expr::Ident(named.orig.clone()) - }; + let value = + if let Some((source, imported)) = self.imports.get(&id!(orig)).cloned() { + self.create_import_access( + &source, + &imported, + match_export_name(&named.orig).1, + ) + } else { + Expr::Ident(orig.clone()) + }; - self.create_export(exported.sym, value, export.span); + self.create_export(match_export_name(&exported).0, value, export.span); } } } diff --git a/packages/transformers/js/core/src/utils.rs b/packages/transformers/js/core/src/utils.rs index 0e8924ead1b..0effc0463b7 100644 --- a/packages/transformers/js/core/src/utils.rs +++ b/packages/transformers/js/core/src/utils.rs @@ -11,21 +11,21 @@ pub fn match_member_expr( idents: Vec<&str>, decls: &HashSet<(JsWord, SyntaxContext)>, ) -> bool { - use ast::{Expr::*, ExprOrSuper::*, Ident, Lit, Str}; + use ast::{Expr, Ident, Lit, MemberProp, Str}; let mut member = expr; let mut idents = idents; while idents.len() > 1 { let expected = idents.pop().unwrap(); - let prop = match &*member.prop { - Lit(Lit::Str(Str { value: ref sym, .. })) => sym, - Ident(Ident { ref sym, .. }) => { - if member.computed { + let prop = match &member.prop { + MemberProp::Computed(comp) => { + if let Expr::Lit(Lit::Str(Str { value: ref sym, .. })) = *comp.expr { + sym + } else { return false; } - - sym } + MemberProp::Ident(Ident { ref sym, .. }) => sym, _ => return false, }; @@ -33,16 +33,13 @@ pub fn match_member_expr( return false; } - match &member.obj { - Expr(expr) => match &**expr { - Member(m) => member = m, - Ident(Ident { ref sym, span, .. }) => { - return idents.len() == 1 - && sym == idents.pop().unwrap() - && !decls.contains(&(sym.clone(), span.ctxt())); - } - _ => return false, - }, + match &*member.obj { + Expr::Member(m) => member = m, + Expr::Ident(Ident { ref sym, span, .. }) => { + return idents.len() == 1 + && sym == idents.pop().unwrap() + && !decls.contains(&(sym.clone(), span.ctxt())); + } _ => return false, } } @@ -57,7 +54,7 @@ pub fn create_require(specifier: swc_atoms::JsWord) -> ast::CallExpr { } ast::CallExpr { - callee: ast::ExprOrSuper::Expr(Box::new(ast::Expr::Ident(ast::Ident::new( + callee: ast::Callee::Expr(Box::new(ast::Expr::Ident(ast::Ident::new( "require".into(), DUMMY_SP, )))), @@ -104,21 +101,26 @@ pub fn match_str(node: &ast::Expr) -> Option<(JsWord, Span)> { } } -pub fn match_str_or_ident(node: &ast::Expr) -> Option<(JsWord, Span)> { - use ast::*; - - if let Expr::Ident(id) = node { - return Some((id.sym.clone(), id.span)); +pub fn match_property_name(node: &ast::MemberExpr) -> Option<(JsWord, Span)> { + match &node.prop { + ast::MemberProp::Computed(s) => match_str(&*s.expr), + ast::MemberProp::Ident(id) => Some((id.sym.clone(), id.span)), + ast::MemberProp::PrivateName(_) => None, } +} - match_str(node) +pub fn match_export_name(name: &ast::ModuleExportName) -> (JsWord, Span) { + match name { + ast::ModuleExportName::Ident(id) => (id.sym.clone(), id.span), + ast::ModuleExportName::Str(s) => (s.value.clone(), s.span), + } } -pub fn match_property_name(node: &ast::MemberExpr) -> Option<(JsWord, Span)> { - if node.computed { - match_str(&*node.prop) - } else { - match_str_or_ident(&*node.prop) +/// Properties like `ExportNamedSpecifier::orig` have to be an Ident if `src` is `None` +pub fn match_export_name_ident(name: &ast::ModuleExportName) -> &ast::Ident { + match name { + ast::ModuleExportName::Ident(id) => id, + ast::ModuleExportName::Str(_) => unreachable!(), } } @@ -131,7 +133,7 @@ pub fn match_require( match node { Expr::Call(call) => match &call.callee { - ExprOrSuper::Expr(expr) => match &**expr { + Callee::Expr(expr) => match &**expr { Expr::Ident(ident) => { if ident.sym == js_word!("require") && !decls.contains(&(ident.sym.clone(), ident.span.ctxt)) @@ -166,18 +168,12 @@ pub fn match_import(node: &ast::Expr, ignore_mark: Mark) -> Option { match node { Expr::Call(call) => match &call.callee { - ExprOrSuper::Expr(expr) => match &**expr { - Expr::Ident(ident) => { - if ident.sym == js_word!("import") && !is_marked(ident.span, ignore_mark) { - if let Some(arg) = call.args.get(0) { - return match_str(&*arg.expr).map(|(name, _)| name); - } - } - - None + Callee::Import(ident) if !is_marked(ident.span, ignore_mark) => { + if let Some(arg) = call.args.get(0) { + return match_str(&*arg.expr).map(|(name, _)| name); } - _ => None, - }, + None + } _ => None, }, _ => None, @@ -345,7 +341,7 @@ macro_rules! fold_member_expr_skip_prop { ) -> swc_ecmascript::ast::MemberExpr { node.obj = node.obj.fold_with(self); - if node.computed { + if let swc_ecmascript::ast::MemberProp::Computed(_) = node.prop { node.prop = node.prop.fold_with(self); } diff --git a/packages/transformers/js/package.json b/packages/transformers/js/package.json index 8e97b9e1358..eb99407c56f 100644 --- a/packages/transformers/js/package.json +++ b/packages/transformers/js/package.json @@ -35,7 +35,7 @@ "@parcel/source-map": "^2.0.0", "@parcel/utils": "2.3.2", "@parcel/workers": "2.3.2", - "@swc/helpers": "^0.2.11", + "@swc/helpers": "^0.3.6", "browserslist": "^4.6.6", "detect-libc": "^1.0.3", "nullthrows": "^1.1.1", diff --git a/yarn.lock b/yarn.lock index 3d6a543153d..2d3d0ed168f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2412,10 +2412,10 @@ "@swc/core-win32-ia32-msvc" "^1.2.106" "@swc/core-win32-x64-msvc" "^1.2.106" -"@swc/helpers@^0.2.11": - version "0.2.11" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.2.11.tgz#34c842dcd8182810b4ab72d0d1fc34b553909e2e" - integrity sha512-0FFPZrCwRDLsbJDKzs1Oo+TAqfAyxnZWZoTF6rUrfWQCYpwuKFj7tAEt/wa830fqCPE5Uk6qIo9KMkPe7Qgukg== +"@swc/helpers@^0.3.6": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.3.6.tgz#b41e77dbf14e9cb138988484563ad9680ae5dc3d" + integrity sha512-xVl7Sddrl9/eMjEMqkH9lT8fLOGCuWHH9VmR2IBKQ8xTcjA6UQw4O3/4oS3xnyZHLtL9vC3P+C0kLneHpiqeEg== "@tootallnate/once@2": version "2.0.0" From 3e893b6aa3ee56389ae393c7af83fb54538168ab Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Fri, 18 Mar 2022 03:39:33 +0100 Subject: [PATCH 04/19] Bump swc and prevent pure comment removal (#7833) --- Cargo.lock | 115 ++++++++++++----------- packages/transformers/js/core/Cargo.toml | 4 +- packages/transformers/js/core/src/lib.rs | 2 + 3 files changed, 62 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 52fd9b59c82..67391037b49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -330,9 +330,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" +checksum = "fdbfe11fe19ff083c48923cf179540e8cd0535903dc35e178a1fdeeb59aef51f" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -351,10 +351,11 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" dependencies = [ + "autocfg", "cfg-if 1.0.0", "crossbeam-utils", "lazy_static", @@ -364,9 +365,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ "cfg-if 1.0.0", "lazy_static", @@ -429,9 +430,9 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0834a35a3fce649144119e18da2a4d8ed12ef3862f47183fd46f625d072d96c" +checksum = "4c8858831f7781322e539ea39e72449c46b059638250c14344fec8d0aa6e539c" dependencies = [ "cfg-if 1.0.0", "num_cpus", @@ -799,9 +800,9 @@ dependencies = [ [[package]] name = "lexical-write-float" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f6202bff3d35ede41a6200227837468bb92e4ecdd437328b1055ed218fb855" +checksum = "8a89ec1d062e481210c309b672f73a0567b7855f21e7d2fae636df44d12e97f9" dependencies = [ "lexical-util", "lexical-write-integer", @@ -820,9 +821,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.119" +version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" +checksum = "ad5c14e80759d0939d013e6ca49930e59fc53dd8e5009132f76240c179380c09" [[package]] name = "libdeflate-sys" @@ -987,13 +988,12 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" [[package]] name = "nom" -version = "7.1.0" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" dependencies = [ "memchr", "minimal-lexical", - "version_check", ] [[package]] @@ -1834,7 +1834,7 @@ checksum = "84fed4a980e12c737171a7b17c5e0a2f4272899266fa0632ea4e31264ebdfdb5" dependencies = [ "ahash", "anyhow", - "dashmap 5.1.0", + "dashmap 5.2.0", "once_cell", "regex", "serde", @@ -1843,9 +1843,9 @@ dependencies = [ [[package]] name = "swc_common" -version = "0.17.15" +version = "0.17.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af06472bfc423fb7b75c483eccfb9b6790db9de0fb2d6ff1ef8369a2551a3707" +checksum = "7935aededdf361eb17ba3ddde021ad0df4774c5b5d902e7b0f6faae7c76d748a" dependencies = [ "ahash", "ast_node", @@ -1872,9 +1872,9 @@ dependencies = [ [[package]] name = "swc_ecma_ast" -version = "0.70.0" +version = "0.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35d736b61d3dceb5a4e18a86d69bfc352aa7136fd3c5a6c2f3353231cd9d839" +checksum = "8ae7b943caae6d3fbae0534ce2df9866efa3d0415199ce7d20c6ef7e4e0b233d" dependencies = [ "is-macro", "num-bigint", @@ -1887,14 +1887,15 @@ dependencies = [ [[package]] name = "swc_ecma_codegen" -version = "0.95.0" +version = "0.98.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fa4a2b82e2bab5bea6472e23b14bd96c462ae9e1e29d9af2ea8ea6d58dcc406" +checksum = "ef9691af1a41fbde638594f2b8593560670adab5c2cc0fd3587481040312797d" dependencies = [ "bitflags", "memchr", "num-bigint", "once_cell", + "rustc-hash", "sourcemap", "swc_atoms", "swc_common", @@ -1905,9 +1906,9 @@ dependencies = [ [[package]] name = "swc_ecma_codegen_macros" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbf826c739281cdb3b3c23883fd1a7586ea1c15b1287530e7123a7fad8f0e25" +checksum = "59949619b2ef45eedb6c399d05f2c3c7bc678b5074b3103bb670f9e05bb99042" dependencies = [ "pmutil", "proc-macro2", @@ -1936,9 +1937,9 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "0.93.0" +version = "0.95.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bcc4ebfd0c5f7c9e5fd03b3dff680d61e997e51147e6f4738ee3274be5ad382" +checksum = "6bbca18d756dddd0a87e101dd07157cd466a22787e9b5447ab85da2faa352bd8" dependencies = [ "either", "enum_kind", @@ -1956,13 +1957,13 @@ dependencies = [ [[package]] name = "swc_ecma_preset_env" -version = "0.106.2" +version = "0.110.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c76924d65625afb0536c433d59a6f63fee0388e0ab7f121bda9ec92a84b4678" +checksum = "13d8929f9552fd9c324a8b22765dfa50b789f0e0069757f3480ececfb11b5136" dependencies = [ "ahash", "anyhow", - "dashmap 5.1.0", + "dashmap 5.2.0", "indexmap", "once_cell", "preset_env_base", @@ -1981,9 +1982,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms" -version = "0.131.0" +version = "0.135.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "484ab8024a62c8f35a408898d0b8aa664e03a992c2f262cda6173274f48d955e" +checksum = "7e19aa898a63dbee9ae4abb505716bc146c55d6ad9e627d617b16bfc827dd36f" dependencies = [ "swc_atoms", "swc_common", @@ -2001,9 +2002,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_base" -version = "0.67.0" +version = "0.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6786157670709b3c9e2a81aee7aef8042b582b4b599f233025b28ca5353a29d9" +checksum = "0e0e50e1414e15cc7b909fb8c79c8b2d9988b83aabe8114fa09a730123c2558c" dependencies = [ "better_scoped_tls", "once_cell", @@ -2021,9 +2022,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_classes" -version = "0.55.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd06b4fa72cd85640fcab59c210c34c8e63f6ea5e547c856febcf18000c0bda" +checksum = "3c16df5d4468e8f54b89eccf0876337c4c672b6434092ec83e71e7c678d1fdd3" dependencies = [ "swc_atoms", "swc_common", @@ -2035,9 +2036,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_compat" -version = "0.80.0" +version = "0.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f622788e39755b4a0b9902e37314fbc59f163d5e9e24c121a95c8352fb00e1e0" +checksum = "12cb92c67a689037b6320bb2e0a421b5c74bfd297f59cfd7c71c0128ff23de02" dependencies = [ "ahash", "arrayvec 0.7.2", @@ -2074,9 +2075,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_module" -version = "0.91.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b050435473be3392bdc665682cf3637c006ea5fe57f6f58cf3be08ae597fab9" +checksum = "a40c273cd4344955105824da8de90e0dfb4e41f4059c3a9accc0292b6b2590b6" dependencies = [ "Inflector", "ahash", @@ -2098,12 +2099,12 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_optimization" -version = "0.101.0" +version = "0.105.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0638979a3445e49125ab28a30dc734c272e66406db5583d9095f459543056ac" +checksum = "1b4c4832545ccd8a62050629f0bea25a8968af107149d01bf60e5b87c9305136" dependencies = [ "ahash", - "dashmap 5.1.0", + "dashmap 5.2.0", "indexmap", "once_cell", "serde_json", @@ -2120,9 +2121,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_proposal" -version = "0.88.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bf987316b088789266b108b9ad87f8479402a76233565ef31807103766bc079" +checksum = "2d5ff5321ecdd0a3e620878e02452a6475b9ffdcaf75a2cf9636c2d31bb85fe0" dependencies = [ "either", "serde", @@ -2139,13 +2140,13 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_react" -version = "0.93.0" +version = "0.97.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd2d009bb8be4149a1b3bb8ea2e4c59c5a26ed5b5ae797563026887480ed9141" +checksum = "3fbf0ee845da10a4018e7c5c5258de5a0b4289fd5e0b4f2d640858fd29c2afe9" dependencies = [ "ahash", "base64 0.13.0", - "dashmap 5.1.0", + "dashmap 5.2.0", "indexmap", "once_cell", "regex", @@ -2164,9 +2165,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_typescript" -version = "0.96.0" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2e388f0b424de694aac45aaad513e7ccb03aeb87ed42781ce353e1346b3d86" +checksum = "5c553fe85a8bcb0fcc6c8929770d556d567991f8061f7a47dc6e962b6b87dbf9" dependencies = [ "serde", "swc_atoms", @@ -2180,9 +2181,9 @@ dependencies = [ [[package]] name = "swc_ecma_utils" -version = "0.72.0" +version = "0.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43689c9f051b48c4ea9eb86b236b27277594a9c4311d3ee88d7007f5d65b1ff5" +checksum = "daa3ba57f53fc15882d2ea288f9a4b6c3a6e97c015d7b9603035be424bc19007" dependencies = [ "indexmap", "once_cell", @@ -2195,9 +2196,9 @@ dependencies = [ [[package]] name = "swc_ecma_visit" -version = "0.56.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b70316301b54ead435ae2660824ba3049de1854710b73395e1b8e615dc0bca6" +checksum = "7588bf6b02705a25356a130acdfec125b6a1dcd5390a5718082ae4f2ede85ee3" dependencies = [ "num-bigint", "swc_atoms", @@ -2209,9 +2210,9 @@ dependencies = [ [[package]] name = "swc_ecmascript" -version = "0.132.1" +version = "0.136.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fa1f0e2b8bcb94f30b276c633743e6d2cf06e5ceb0561fe1bb55d47d020921e" +checksum = "5eb75ac51d44c811e4527ce30873a8ef1bd8f2435e33ec6a5dc62936dbfdc451" dependencies = [ "swc_ecma_ast", "swc_ecma_codegen", @@ -2645,9 +2646,9 @@ checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" [[package]] name = "xxhash-rust" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886f21441c6731b9e06a9fdacbc5e29319c17a4069c2a511d80349874864702d" +checksum = "83a16b7b403377d61184bb601d8349a4ff2c4cec08a305d004f710b7eaafef24" [[package]] name = "zopfli" diff --git a/packages/transformers/js/core/Cargo.toml b/packages/transformers/js/core/Cargo.toml index 250ed2ecf78..ecfac518dff 100644 --- a/packages/transformers/js/core/Cargo.toml +++ b/packages/transformers/js/core/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" crate-type = ["rlib"] [dependencies] -swc_ecmascript = { version = "0.132.0", features = ["parser", "transforms", "module", "optimization", "react", "typescript", "utils", "visit", "codegen", "utils", "preset_env"] } -swc_common = { version = "0.17.15", features = ["tty-emitter", "sourcemap"] } +swc_ecmascript = { version = "0.136.0", features = ["parser", "transforms", "module", "optimization", "react", "typescript", "utils", "visit", "codegen", "utils", "preset_env"] } +swc_common = { version = "0.17.17", features = ["tty-emitter", "sourcemap"] } swc_atoms = "0.2.9" indoc = "1.0.3" serde = "1.0.123" diff --git a/packages/transformers/js/core/src/lib.rs b/packages/transformers/js/core/src/lib.rs index 4dcb6924e18..9fd7ba2222e 100644 --- a/packages/transformers/js/core/src/lib.rs +++ b/packages/transformers/js/core/src/lib.rs @@ -35,6 +35,7 @@ use swc_ecmascript::codegen::text_writer::JsWriter; use swc_ecmascript::parser::lexer::Lexer; use swc_ecmascript::parser::{EsConfig, PResult, Parser, StringInput, Syntax, TsConfig}; use swc_ecmascript::preset_env::{preset_env, Mode::Entry, Targets, Version, Versions}; +use swc_ecmascript::transforms::fixer::paren_remover; use swc_ecmascript::transforms::resolver::resolver_with_mark; use swc_ecmascript::transforms::{ compat::reserved_words::reserved_words, fixer, helpers, hygiene, @@ -340,6 +341,7 @@ pub fn transform(config: Config) -> Result { }, config.source_type != SourceType::Script ), + paren_remover(Some(&comments)), // Simplify expressions and remove dead branches so that we // don't include dependencies inside conditionals that are always false. expr_simplifier(Default::default()), From fe51929197281ce62b537617be7bfde69f7e1a6c Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Fri, 18 Mar 2022 03:40:06 +0100 Subject: [PATCH 05/19] Enable parsing static initialization blocks (#7839) --- packages/transformers/js/core/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/transformers/js/core/src/lib.rs b/packages/transformers/js/core/src/lib.rs index 9fd7ba2222e..1ec1f8c50d3 100644 --- a/packages/transformers/js/core/src/lib.rs +++ b/packages/transformers/js/core/src/lib.rs @@ -510,6 +510,7 @@ fn parse( Syntax::Es(EsConfig { jsx: config.is_jsx, export_default_from: true, + static_blocks: true, decorators: config.decorators, ..Default::default() }) From 7b168519ae02866d3d351a55c3504d9ca5f727df Mon Sep 17 00:00:00 2001 From: Shinobu Hayashi Date: Thu, 17 Mar 2022 19:40:29 -0700 Subject: [PATCH 06/19] Feature: pick PORT number also from .env file (#7819) --- packages/core/core/src/resolveOptions.js | 57 +++++++++++++++++++----- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/packages/core/core/src/resolveOptions.js b/packages/core/core/src/resolveOptions.js index 1ce2e208571..42c52979296 100644 --- a/packages/core/core/src/resolveOptions.js +++ b/packages/core/core/src/resolveOptions.js @@ -4,6 +4,7 @@ import type { FilePath, InitialParcelOptions, DependencySpecifier, + InitialServerOptions, } from '@parcel/types'; import type {FileSystem} from '@parcel/fs'; import type {ParcelOptions} from './types'; @@ -95,6 +96,19 @@ export default async function resolveOptions( throw new Error('Lazy bundling does not work with content hashing'); } + let env = { + ...(await loadDotEnv( + initialOptions.env ?? {}, + inputFS, + path.join(projectRoot, 'index'), + projectRoot, + )), + ...process.env, + ...initialOptions.env, + }; + + let port = determinePort(initialOptions.serveOptions, env.PORT); + return { config: getRelativeConfigSpecifier( inputFS, @@ -107,16 +121,7 @@ export default async function resolveOptions( initialOptions.defaultConfig, ), shouldPatchConsole: initialOptions.shouldPatchConsole ?? false, - env: { - ...(await loadDotEnv( - initialOptions.env ?? {}, - inputFS, - path.join(projectRoot, 'index'), - projectRoot, - )), - ...process.env, - ...initialOptions.env, - }, + env, mode, shouldAutoInstall: initialOptions.shouldAutoInstall ?? false, hmrOptions: initialOptions.hmrOptions ?? null, @@ -126,6 +131,7 @@ export default async function resolveOptions( ? { ...initialOptions.serveOptions, distDir: distDir ?? path.join(outputCwd, 'dist'), + port, } : false, shouldDisableCache: initialOptions.shouldDisableCache ?? false, @@ -178,3 +184,34 @@ function getRelativeConfigSpecifier( return specifier; } } + +function determinePort( + initialServerOptions: InitialServerOptions | false | void, + portInEnv: string | void, + defaultPort: number = 1234, +): number { + function parsePort(port: string): number | void { + let parsedPort = Number(port); + + // return undefined if port number defined in .env is not valid integer + if (!Number.isInteger(parsedPort)) { + return undefined; + } + return parsedPort; + } + + if (!initialServerOptions) { + return typeof portInEnv !== 'undefined' + ? parsePort(portInEnv) ?? defaultPort + : defaultPort; + } + + // if initialServerOptions.port is equal to defaultPort, then this means that port number is provided via PORT=~~~~ on cli. In this case, we should ignore port number defined in .env. + if (initialServerOptions.port !== defaultPort) { + return initialServerOptions.port; + } + + return typeof portInEnv !== 'undefined' + ? parsePort(portInEnv) ?? defaultPort + : defaultPort; +} From 96c847b21361bcd2f7c8712752e5376e1f80b27e Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Fri, 18 Mar 2022 12:44:03 -0400 Subject: [PATCH 07/19] Move to @parcel/css by default (#7821) --- packages/configs/default/index.json | 2 +- packages/configs/default/package.json | 2 +- .../integration-tests/test/css-modules.js | 892 +++++++++--------- packages/core/integration-tests/test/css.js | 787 +++++++-------- packages/core/test-utils/src/.parcelrc-css | 10 - packages/optimizers/css/package.json | 3 +- packages/optimizers/css/src/CSSOptimizer.js | 46 + .../css-experimental/package.json | 30 - .../css-experimental/src/CSSTransformer.js | 232 ----- packages/transformers/css/package.json | 11 +- .../transformers/css/src/CSSTransformer.js | 520 ++++------ packages/transformers/postcss/package.json | 4 +- .../postcss/src/PostCSSTransformer.js | 76 +- .../transformers/postcss/src/loadConfig.js | 72 +- yarn.lock | 96 +- 15 files changed, 1225 insertions(+), 1558 deletions(-) delete mode 100644 packages/core/test-utils/src/.parcelrc-css delete mode 100644 packages/transformers/css-experimental/package.json delete mode 100644 packages/transformers/css-experimental/src/CSSTransformer.js diff --git a/packages/configs/default/index.json b/packages/configs/default/index.json index bda82bd3089..e6d9a21e2a9 100644 --- a/packages/configs/default/index.json +++ b/packages/configs/default/index.json @@ -53,7 +53,7 @@ ], "optimizers": { "data-url:*": ["...", "@parcel/optimizer-data-url"], - "*.css": ["@parcel/optimizer-cssnano"], + "*.css": ["@parcel/optimizer-css"], "*.{html,xhtml}": ["@parcel/optimizer-htmlnano"], "*.{js,mjs,cjs}": ["@parcel/optimizer-terser"], "*.svg": ["@parcel/optimizer-svgo"], diff --git a/packages/configs/default/package.json b/packages/configs/default/package.json index 8a8f47a369f..f6f94cad732 100644 --- a/packages/configs/default/package.json +++ b/packages/configs/default/package.json @@ -21,7 +21,7 @@ "@parcel/bundler-default": "2.3.2", "@parcel/compressor-raw": "2.3.2", "@parcel/namer-default": "2.3.2", - "@parcel/optimizer-cssnano": "2.3.2", + "@parcel/optimizer-css": "2.3.2", "@parcel/optimizer-htmlnano": "2.3.2", "@parcel/optimizer-image": "2.3.2", "@parcel/optimizer-svgo": "2.3.2", diff --git a/packages/core/integration-tests/test/css-modules.js b/packages/core/integration-tests/test/css-modules.js index de7a660b36d..f591e517873 100644 --- a/packages/core/integration-tests/test/css-modules.js +++ b/packages/core/integration-tests/test/css-modules.js @@ -1,7 +1,7 @@ import assert from 'assert'; import path from 'path'; import { - bundle as originalBundle, + bundle, run, assertBundles, distDir, @@ -10,486 +10,442 @@ import { import postcss from 'postcss'; describe('css modules', () => { - for (let name of ['old', 'new']) { - describe(name, () => { - let bundle = (entries, opts = {}) => { - if (name === 'new') { - // $FlowFixMe - opts.defaultConfig = - path.dirname(require.resolve('@parcel/test-utils')) + - '/.parcelrc-css'; - } - return originalBundle(entries, opts); - }; - - it('should support transforming css modules (require)', async () => { - let b = await bundle( - path.join(__dirname, '/integration/postcss-modules-cjs/index.js'), - ); - - assertBundles(b, [ - { - name: 'index.js', - assets: ['index.js', 'foo.module.css'], - }, - { - name: 'index.css', - assets: ['index.css', 'foo.module.css'], - }, - ]); - - let output = await run(b); - assert.equal(typeof output, 'function'); - - let value = output(); - assert(/foo_[0-9a-zA-Z]/.test(value)); - - let cssClass = value.match(/(foo_[0-9a-zA-Z])/)[1]; - - let css = await outputFS.readFile( - path.join(distDir, 'index.css'), - 'utf8', - ); - assert(css.includes(`.${cssClass}`)); - }); - - it('should support transforming css modules (import default)', async () => { - let b = await bundle( - path.join( - __dirname, - '/integration/postcss-modules-import-default/index.js', - ), - {mode: 'production'}, - ); - - assertBundles(b, [ - { - name: 'index.js', - assets: ['index.js', 'style.module.css'], - }, - { - name: 'index.css', - assets: ['style.module.css'], - }, - ]); - - let output = await run(b); - assert(/b-2_[0-9a-zA-Z]/.test(output)); - - let css = await outputFS.readFile( - b.getBundles().find(b => b.type === 'css').filePath, - 'utf8', - ); - let includedRules = new Set(); - postcss.parse(css).walkRules(rule => { - includedRules.add(rule.selector); - }); - assert(includedRules.has('.page')); - assert(includedRules.has(`.${output}`)); - }); - - it('should tree shake unused css modules classes with a namespace import', async () => { - let b = await bundle( - path.join( - __dirname, - '/integration/postcss-modules-import-namespace/index.js', - ), - {mode: 'production'}, - ); - - assertBundles(b, [ - { - name: 'index.js', - assets: ['index.js', 'style.module.css'], - }, - { - name: 'index.css', - assets: ['global.css', 'style.module.css'], - }, - ]); - - let js = await outputFS.readFile( - b.getBundles().find(b => b.type === 'js').filePath, - 'utf8', - ); - assert(!js.includes('unused')); - - let output = await run(b); - assert(/b-2_[0-9a-zA-Z]/.test(output)); - - let css = await outputFS.readFile( - b.getBundles().find(b => b.type === 'css').filePath, - 'utf8', - ); - let includedRules = new Set(); - postcss.parse(css).walkRules(rule => { - includedRules.add(rule.selector); - }); - assert.deepStrictEqual( - includedRules, - new Set(['body', `.${output}`, '.page']), - ); - }); - - it('should produce correct css without symbol propagation for css modules classes with a namespace import', async () => { - let b = await bundle( + it('should support transforming css modules (require)', async () => { + let b = await bundle( + path.join(__dirname, '/integration/postcss-modules-cjs/index.js'), + ); + + assertBundles(b, [ + { + name: 'index.js', + assets: ['index.js', 'foo.module.css'], + }, + { + name: 'index.css', + assets: ['index.css', 'foo.module.css'], + }, + ]); + + let output = await run(b); + assert.equal(typeof output, 'function'); + + let value = output(); + assert(/foo_[0-9a-zA-Z]/.test(value)); + + let cssClass = value.match(/(foo_[0-9a-zA-Z])/)[1]; + + let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8'); + assert(css.includes(`.${cssClass}`)); + }); + + it('should support transforming css modules (import default)', async () => { + let b = await bundle( + path.join( + __dirname, + '/integration/postcss-modules-import-default/index.js', + ), + {mode: 'production'}, + ); + + assertBundles(b, [ + { + name: 'index.js', + assets: ['index.js', 'style.module.css'], + }, + { + name: 'index.css', + assets: ['style.module.css'], + }, + ]); + + let output = await run(b); + assert(/b-2_[0-9a-zA-Z]/.test(output)); + + let css = await outputFS.readFile( + b.getBundles().find(b => b.type === 'css').filePath, + 'utf8', + ); + let includedRules = new Set(); + postcss.parse(css).walkRules(rule => { + includedRules.add(rule.selector); + }); + assert(includedRules.has('.page')); + assert(includedRules.has(`.${output}`)); + }); + + it('should tree shake unused css modules classes with a namespace import', async () => { + let b = await bundle( + path.join( + __dirname, + '/integration/postcss-modules-import-namespace/index.js', + ), + {mode: 'production'}, + ); + + assertBundles(b, [ + { + name: 'index.js', + assets: ['index.js', 'style.module.css'], + }, + { + name: 'index.css', + assets: ['global.css', 'style.module.css'], + }, + ]); + + let js = await outputFS.readFile( + b.getBundles().find(b => b.type === 'js').filePath, + 'utf8', + ); + assert(!js.includes('unused')); + + let output = await run(b); + assert(/b-2_[0-9a-zA-Z]/.test(output)); + + let css = await outputFS.readFile( + b.getBundles().find(b => b.type === 'css').filePath, + 'utf8', + ); + let includedRules = new Set(); + postcss.parse(css).walkRules(rule => { + includedRules.add(rule.selector); + }); + assert.deepStrictEqual( + includedRules, + new Set(['body', `.${output}`, '.page']), + ); + }); + + it('should produce correct css without symbol propagation for css modules classes with a namespace import', async () => { + let b = await bundle( + path.join( + __dirname, + '/integration/postcss-modules-import-namespace/index.js', + ), + { + mode: 'production', + defaultTargetOptions: { + shouldScopeHoist: false, + }, + }, + ); + + assertBundles(b, [ + { + name: 'index.js', + assets: ['index.js', 'style.module.css'], + }, + { + name: 'index.css', + assets: ['global.css', 'style.module.css'], + }, + ]); + + let {output} = await run(b, null, {require: false}); + assert(/b-2_[0-9a-zA-Z]/.test(output)); + + let css = await outputFS.readFile( + b.getBundles().find(b => b.type === 'css').filePath, + 'utf8', + ); + let includedRules = new Set(); + postcss.parse(css).walkRules(rule => { + includedRules.add(rule.selector); + }); + assert(includedRules.has('body')); + assert(includedRules.has(`.${output}`)); + assert(includedRules.has('.page')); + }); + + it('should support importing css modules with a non-static namespace import', async () => { + let b = await bundle( + path.join( + __dirname, + '/integration/postcss-modules-import-namespace-whole/index.js', + ), + {mode: 'production'}, + ); + + assertBundles(b, [ + { + name: 'index.js', + assets: ['index.js', 'style.module.css'], + }, + { + name: 'index.css', + assets: ['global.css', 'style.module.css'], + }, + ]); + + let js = await outputFS.readFile( + b.getBundles().find(b => b.type === 'js').filePath, + 'utf8', + ); + assert(js.includes('unused')); + + let output = await run(b); + assert(/b-2_[0-9a-zA-Z]/.test(output['b-2'])); + assert(/unused_[0-9a-zA-Z]/.test(output['unused'])); + + let css = await outputFS.readFile( + b.getBundles().find(b => b.type === 'css').filePath, + 'utf8', + ); + let includedRules = new Set(); + postcss.parse(css).walkRules(rule => { + includedRules.add(rule.selector); + }); + assert.deepStrictEqual( + includedRules, + new Set(['body', `.${output['b-2']}`, `.${output['unused']}`, '.page']), + ); + }); + + it('should support css modules composes imports', async () => { + let b = await bundle( + path.join(__dirname, '/integration/postcss-composes/index.js'), + ); + + assertBundles(b, [ + { + name: 'index.js', + assets: [ + 'index.js', + 'composes-1.module.css', + 'composes-2.module.css', + 'mixins.module.css', + ], + }, + { + name: 'index.css', + assets: [ + 'composes-1.module.css', + 'composes-2.module.css', + 'mixins.module.css', + ], + }, + ]); + + let output = await run(b); + assert.equal(typeof output, 'function'); + + let value = output(); + const composes1Classes = value.composes1.split(' '); + const composes2Classes = value.composes2.split(' '); + assert(composes1Classes[0].startsWith('composes1_')); + assert(composes1Classes[1].startsWith('test_')); + assert(composes2Classes[0].startsWith('composes2_')); + assert(composes2Classes[1].startsWith('test_')); + + let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8'); + let cssClass1 = value.composes1.match(/(composes1_[0-9a-zA-Z]+)/)[1]; + assert(css.includes(`.${cssClass1}`)); + let cssClass2 = value.composes2.match(/(composes2_[0-9a-zA-Z]+)/)[1]; + assert(css.includes(`.${cssClass2}`)); + }); + + it('should not include css twice for composes imports', async () => { + let b = await bundle( + path.join(__dirname, '/integration/postcss-composes/index.js'), + ); + + await run(b); + + let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8'); + assert.equal( + css.indexOf('height: 100px;'), + css.lastIndexOf('height: 100px;'), + ); + }); + + it('should support composes imports for sass', async () => { + let b = await bundle( + path.join(__dirname, '/integration/postcss-composes/index2.js'), + ); + + assertBundles(b, [ + { + name: 'index2.js', + assets: ['index2.js', 'composes-3.module.css', 'mixins.module.scss'], + }, + { + name: 'index2.css', + assets: ['composes-3.module.css', 'mixins.module.scss'], + }, + ]); + + let output = await run(b); + assert.equal(typeof output, 'function'); + + let value = output(); + const composes3Classes = value.composes3.split(' '); + assert(composes3Classes[0].startsWith('composes3_')); + assert(composes3Classes[1].startsWith('test_')); + + let css = await outputFS.readFile(path.join(distDir, 'index2.css'), 'utf8'); + assert(css.includes('height: 200px;')); + }); + + it('should support composes imports with custom path names', async () => { + let b = await bundle( + path.join(__dirname, '/integration/postcss-composes/index3.js'), + ); + + assertBundles(b, [ + { + name: 'index3.js', + assets: ['index3.js', 'composes-4.module.css', 'mixins.module.css'], + }, + { + name: 'index3.css', + assets: ['composes-4.module.css', 'mixins.module.css'], + }, + ]); + + let output = await run(b); + assert.equal(typeof output, 'function'); + + let value = output(); + const composes4Classes = value.composes4.split(' '); + assert(composes4Classes[0].startsWith('composes4_')); + assert(composes4Classes[1].startsWith('test_')); + + let css = await outputFS.readFile(path.join(distDir, 'index3.css'), 'utf8'); + assert(css.includes('height: 100px;')); + }); + + it('should support deep nested composes imports', async () => { + let b = await bundle( + path.join(__dirname, '/integration/postcss-composes/index4.js'), + ); + + assertBundles(b, [ + { + name: 'index4.js', + assets: [ + 'index4.js', + 'composes-5.module.css', + 'mixins-intermediate.module.css', + 'mixins.module.css', + ], + }, + { + name: 'index4.css', + assets: [ + 'composes-5.module.css', + 'mixins-intermediate.module.css', + 'mixins.module.css', + ], + }, + ]); + + let output = await run(b); + assert.equal(typeof output, 'function'); + + let value = output(); + const composes5Classes = value.composes5.split(' '); + assert(composes5Classes[0].startsWith('composes5_')); + assert(composes5Classes[1].startsWith('intermediate_')); + assert(composes5Classes[2].startsWith('test_')); + + let css = await outputFS.readFile(path.join(distDir, 'index4.css'), 'utf8'); + assert(css.includes('height: 100px;')); + assert(css.includes('height: 300px;')); + assert(css.indexOf('.test_') < css.indexOf('.intermediate_')); + }); + + it('should support composes imports for multiple selectors', async () => { + let b = await bundle( + path.join(__dirname, '/integration/postcss-composes/index5.js'), + ); + + assertBundles(b, [ + { + name: 'index5.js', + assets: ['index5.js', 'composes-6.module.css', 'mixins.module.css'], + }, + { + name: 'index5.css', + assets: ['composes-6.module.css', 'mixins.module.css'], + }, + ]); + + let output = await run(b); + assert.equal(typeof output, 'function'); + + let value = output(); + const composes6Classes = value.composes6.split(' '); + assert(composes6Classes[0].startsWith('composes6_')); + assert(composes6Classes[1].startsWith('test_')); + assert(composes6Classes[2].startsWith('test-2_')); + }); + + it('should throw an error when importing a missing class', async function () { + await assert.rejects( + () => + bundle( path.join( __dirname, - '/integration/postcss-modules-import-namespace/index.js', + '/integration/no-export-error-with-correct-filetype/src/App.jsx', ), { - mode: 'production', + shouldDisableCache: true, defaultTargetOptions: { - shouldScopeHoist: false, + shouldScopeHoist: true, }, }, - ); - - assertBundles(b, [ - { - name: 'index.js', - assets: ['index.js', 'style.module.css'], - }, - { - name: 'index.css', - assets: ['global.css', 'style.module.css'], - }, - ]); - - let {output} = await run(b, null, {require: false}); - assert(/b-2_[0-9a-zA-Z]/.test(output)); - - let css = await outputFS.readFile( - b.getBundles().find(b => b.type === 'css').filePath, - 'utf8', - ); - let includedRules = new Set(); - postcss.parse(css).walkRules(rule => { - includedRules.add(rule.selector); - }); - assert(includedRules.has('body')); - assert(includedRules.has(`.${output}`)); - assert(includedRules.has('.page')); - }); - - it('should support importing css modules with a non-static namespace import', async () => { - let b = await bundle( - path.join( - __dirname, - '/integration/postcss-modules-import-namespace-whole/index.js', - ), - {mode: 'production'}, - ); - - assertBundles(b, [ - { - name: 'index.js', - assets: ['index.js', 'style.module.css'], - }, - { - name: 'index.css', - assets: ['global.css', 'style.module.css'], - }, - ]); - - let js = await outputFS.readFile( - b.getBundles().find(b => b.type === 'js').filePath, - 'utf8', - ); - assert(js.includes('unused')); - - let output = await run(b); - assert(/b-2_[0-9a-zA-Z]/.test(output['b-2'])); - assert(/unused_[0-9a-zA-Z]/.test(output['unused'])); - - let css = await outputFS.readFile( - b.getBundles().find(b => b.type === 'css').filePath, - 'utf8', - ); - let includedRules = new Set(); - postcss.parse(css).walkRules(rule => { - includedRules.add(rule.selector); - }); - assert.deepStrictEqual( - includedRules, - new Set([ - 'body', - `.${output['b-2']}`, - `.${output['unused']}`, - '.page', - ]), - ); - }); - - it('should support css modules composes imports', async () => { - let b = await bundle( - path.join(__dirname, '/integration/postcss-composes/index.js'), - ); - - assertBundles(b, [ - { - name: 'index.js', - assets: [ - 'index.js', - 'composes-1.module.css', - 'composes-2.module.css', - 'mixins.module.css', - ], - }, - { - name: 'index.css', - assets: [ - 'composes-1.module.css', - 'composes-2.module.css', - 'mixins.module.css', - ], - }, - ]); - - let output = await run(b); - assert.equal(typeof output, 'function'); - - let value = output(); - const composes1Classes = value.composes1.split(' '); - const composes2Classes = value.composes2.split(' '); - assert(composes1Classes[0].startsWith('composes1_')); - assert(composes1Classes[1].startsWith('test_')); - assert(composes2Classes[0].startsWith('composes2_')); - assert(composes2Classes[1].startsWith('test_')); - - let css = await outputFS.readFile( - path.join(distDir, 'index.css'), - 'utf8', - ); - let cssClass1 = value.composes1.match(/(composes1_[0-9a-zA-Z]+)/)[1]; - assert(css.includes(`.${cssClass1}`)); - let cssClass2 = value.composes2.match(/(composes2_[0-9a-zA-Z]+)/)[1]; - assert(css.includes(`.${cssClass2}`)); - }); - - it('should not include css twice for composes imports', async () => { - let b = await bundle( - path.join(__dirname, '/integration/postcss-composes/index.js'), - ); - - await run(b); - - let css = await outputFS.readFile( - path.join(distDir, 'index.css'), - 'utf8', - ); - assert.equal( - css.indexOf('height: 100px;'), - css.lastIndexOf('height: 100px;'), - ); - }); - - it('should support composes imports for sass', async () => { - let b = await bundle( - path.join(__dirname, '/integration/postcss-composes/index2.js'), - ); - - assertBundles(b, [ - { - name: 'index2.js', - assets: [ - 'index2.js', - 'composes-3.module.css', - 'mixins.module.scss', - ], - }, - { - name: 'index2.css', - assets: ['composes-3.module.css', 'mixins.module.scss'], - }, - ]); - - let output = await run(b); - assert.equal(typeof output, 'function'); - - let value = output(); - const composes3Classes = value.composes3.split(' '); - assert(composes3Classes[0].startsWith('composes3_')); - assert(composes3Classes[1].startsWith('test_')); - - let css = await outputFS.readFile( - path.join(distDir, 'index2.css'), - 'utf8', - ); - assert(css.includes('height: 200px;')); - }); - - it('should support composes imports with custom path names', async () => { - let b = await bundle( - path.join(__dirname, '/integration/postcss-composes/index3.js'), - ); - - assertBundles(b, [ - { - name: 'index3.js', - assets: ['index3.js', 'composes-4.module.css', 'mixins.module.css'], - }, + ), + { + name: 'BuildError', + diagnostics: [ { - name: 'index3.css', - assets: ['composes-4.module.css', 'mixins.module.css'], - }, - ]); - - let output = await run(b); - assert.equal(typeof output, 'function'); - - let value = output(); - const composes4Classes = value.composes4.split(' '); - assert(composes4Classes[0].startsWith('composes4_')); - assert(composes4Classes[1].startsWith('test_')); - - let css = await outputFS.readFile( - path.join(distDir, 'index3.css'), - 'utf8', - ); - assert(css.includes('height: 100px;')); - }); - - it('should support deep nested composes imports', async () => { - let b = await bundle( - path.join(__dirname, '/integration/postcss-composes/index4.js'), - ); - - assertBundles(b, [ - { - name: 'index4.js', - assets: [ - 'index4.js', - 'composes-5.module.css', - 'mixins-intermediate.module.css', - 'mixins.module.css', - ], - }, - { - name: 'index4.css', - assets: [ - 'composes-5.module.css', - 'mixins-intermediate.module.css', - 'mixins.module.css', - ], - }, - ]); - - let output = await run(b); - assert.equal(typeof output, 'function'); - - let value = output(); - const composes5Classes = value.composes5.split(' '); - assert(composes5Classes[0].startsWith('composes5_')); - assert(composes5Classes[1].startsWith('intermediate_')); - assert(composes5Classes[2].startsWith('test_')); - - let css = await outputFS.readFile( - path.join(distDir, 'index4.css'), - 'utf8', - ); - assert(css.includes('height: 100px;')); - assert(css.includes('height: 300px;')); - assert(css.indexOf('.test_') < css.indexOf('.intermediate_')); - }); - - it('should support composes imports for multiple selectors', async () => { - let b = await bundle( - path.join(__dirname, '/integration/postcss-composes/index5.js'), - ); - - assertBundles(b, [ - { - name: 'index5.js', - assets: ['index5.js', 'composes-6.module.css', 'mixins.module.css'], - }, - { - name: 'index5.css', - assets: ['composes-6.module.css', 'mixins.module.css'], - }, - ]); - - let output = await run(b); - assert.equal(typeof output, 'function'); - - let value = output(); - const composes6Classes = value.composes6.split(' '); - assert(composes6Classes[0].startsWith('composes6_')); - assert(composes6Classes[1].startsWith('test_')); - assert(composes6Classes[2].startsWith('test-2_')); - }); - - it('should throw an error when importing a missing class', async function () { - await assert.rejects( - () => - bundle( - path.join( - __dirname, - '/integration/no-export-error-with-correct-filetype/src/App.jsx', - ), + codeFrames: [ { - shouldDisableCache: true, - defaultTargetOptions: { - shouldScopeHoist: true, - }, - }, - ), - { - name: 'BuildError', - diagnostics: [ - { - codeFrames: [ + filePath: path.join( + __dirname, + '/integration/no-export-error-with-correct-filetype/src/App.jsx', + ), + language: 'js', + codeHighlights: [ { - filePath: path.join( - __dirname, - '/integration/no-export-error-with-correct-filetype/src/App.jsx', - ), - language: 'js', - codeHighlights: [ - { - end: { - column: 45, - line: 7, - }, - start: { - column: 28, - line: 7, - }, - }, - ], + end: { + column: 45, + line: 7, + }, + start: { + column: 28, + line: 7, + }, }, ], - message: - "integration/no-export-error-with-correct-filetype/src/app.module.css does not export 'notExisting'", - origin: '@parcel/core', }, ], + message: + "integration/no-export-error-with-correct-filetype/src/app.module.css does not export 'notExisting'", + origin: '@parcel/core', }, - ); - }); - - it('should fall back to postcss for legacy css modules', async function () { - let b = await bundle( - path.join(__dirname, '/integration/css-modules-legacy/index.js'), - ); - - assertBundles(b, [ - { - name: 'index.js', - assets: ['index.js', 'index.module.css'], - }, - { - name: 'index.css', - assets: ['index.module.css'], - }, - ]); - - let css = await outputFS.readFile( - path.join(distDir, 'index.css'), - 'utf8', - ); - assert(css.includes('color: red')); - }); - }); - } + ], + }, + ); + }); + + it('should fall back to postcss for legacy css modules', async function () { + let b = await bundle( + path.join(__dirname, '/integration/css-modules-legacy/index.js'), + ); + + assertBundles(b, [ + { + name: 'index.js', + assets: ['index.js', 'index.module.css'], + }, + { + name: 'index.css', + assets: ['index.module.css'], + }, + ]); + + let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8'); + assert(css.includes('color: red')); + }); }); diff --git a/packages/core/integration-tests/test/css.js b/packages/core/integration-tests/test/css.js index 45e575a0874..dcb3adab669 100644 --- a/packages/core/integration-tests/test/css.js +++ b/packages/core/integration-tests/test/css.js @@ -2,7 +2,7 @@ import assert from 'assert'; import path from 'path'; import { - bundle as originalBundle, + bundle, run, assertBundles, distDir, @@ -16,467 +16,410 @@ describe('css', () => { await removeDistDirectory(); }); - for (let name of ['old', 'new']) { - describe(name, () => { - let bundle = (entries, opts = {}) => { - if (name === 'new') { - // $FlowFixMe - opts.defaultConfig = - path.dirname(require.resolve('@parcel/test-utils')) + - '/.parcelrc-css'; - } - return originalBundle(entries, opts); - }; - - it('should produce two bundles when importing a CSS file', async () => { - let b = await bundle(path.join(__dirname, '/integration/css/index.js')); - - assertBundles(b, [ - { - name: 'index.js', - assets: ['index.js', 'local.js'], - }, - { - name: 'index.css', - assets: ['index.css', 'local.css'], - }, - ]); - - let output = await run(b); - assert.equal(typeof output, 'function'); - assert.equal(output(), 3); - }); - - it('should bundle css dependencies in the correct, postorder traversal order', async () => { - let b = await bundle( - path.join(__dirname, '/integration/css-order/a.css'), - ); - - // Given a tree of css with imports: - // A - // / \ - // B E - // / \ - // C D - // - // (A imports B (which imports C and D) and E) - // - // ...styles should be applied in the order C, D, B, E, A - - assertBundles(b, [ - { - name: 'a.css', - assets: ['a.css', 'b.css', 'c.css', 'd.css', 'e.css'], - }, - ]); - - let css = await outputFS.readFile(path.join(distDir, 'a.css'), 'utf8'); - assert.ok( - css.indexOf('.c {') < css.indexOf('.d {') && - css.indexOf('.d {') < css.indexOf('.b {') && - css.indexOf('.b {') < css.indexOf('.e {') && - css.indexOf('.e {') < css.indexOf('.a {'), - ); - }); - - it('should support loading a CSS bundle along side dynamic imports', async () => { - let b = await bundle( - path.join(__dirname, '/integration/dynamic-css/index.js'), - ); - - assertBundles(b, [ - { - name: 'index.js', - assets: [ - 'bundle-url.js', - 'cacheLoader.js', - 'css-loader.js', - 'index.js', - 'js-loader.js', - ], - }, - {name: /local\.[0-9a-f]{8}\.js/, assets: ['local.js']}, - {name: /local\.[0-9a-f]{8}\.css/, assets: ['local.css']}, - {name: 'index.css', assets: ['index.css']}, - ]); - - let output = await run(b); - assert.equal(typeof output, 'function'); - assert.equal(await output(), 3); - }); - - it('should support importing CSS from a CSS file', async function () { - let b = await bundle( - path.join(__dirname, '/integration/css-import/index.js'), - ); - - assertBundles(b, [ - { - name: 'index.js', - assets: ['index.js'], - }, - { - name: 'index.css', - assets: ['index.css', 'other.css', 'local.css'], - }, - ]); - - let output = await run(b); - assert.equal(typeof output, 'function'); - assert.equal(output(), 2); - - let css = await outputFS.readFile( - path.join(distDir, '/index.css'), - 'utf8', - ); - assert(css.includes('.local')); - assert(css.includes('.other')); - assert(/@media print {\s*.other/.test(css)); - assert(css.includes('.index')); - }); - - it('should support linking to assets with url() from CSS', async function () { - let b = await bundle( - path.join(__dirname, '/integration/css-url/index.js'), - ); - - assertBundles(b, [ - { - name: 'index.js', - assets: ['index.js'], - }, - { - name: 'index.css', - assets: ['index.css'], - }, - { - type: 'woff2', - assets: ['test.woff2'], - }, - ]); - - let output = await run(b); - assert.equal(typeof output, 'function'); - assert.equal(output(), 2); - - let css = await outputFS.readFile( - path.join(distDir, 'index.css'), - 'utf8', - ); - assert(/url\("test\.[0-9a-f]+\.woff2"\)/.test(css)); - assert(css.includes('url("http://google.com")')); - assert(css.includes('.index')); - assert(css.includes('url("data:image/gif;base64,quotes")')); - assert(css.includes('.quotes')); - assert(css.includes('url("data:image/gif;base64,no-quote")')); - assert(css.includes('.no-quote')); - - assert( - await outputFS.exists( - path.join( - distDir, - css.match(/url\("(test\.[0-9a-f]+\.woff2)"\)/)[1], - ), - ), - ); - }); - - it('should support linking to assets with url() from CSS in production', async function () { - let b = await bundle( - path.join(__dirname, '/integration/css-url/index.js'), - { - defaultTargetOptions: { - shouldOptimize: true, - }, - }, - ); + it('should produce two bundles when importing a CSS file', async () => { + let b = await bundle(path.join(__dirname, '/integration/css/index.js')); - assertBundles(b, [ - { - name: 'index.js', - assets: ['index.js'], - }, - { - name: 'index.css', - assets: ['index.css'], - }, - { - type: 'woff2', - assets: ['test.woff2'], - }, - ]); - - let output = await run(b); - assert.equal(typeof output, 'function'); - assert.equal(output(), 2); - - let css = await outputFS.readFile( - path.join(distDir, 'index.css'), - 'utf8', - ); - assert( - /url\(test\.[0-9a-f]+\.woff2\)/.test(css), - 'woff ext found in css', - ); - assert(css.includes('url(http://google.com)'), 'url() found'); - assert(css.includes('.index'), '.index found'); - assert(/url\("?data:image\/gif;base64,quotes"?\)/.test(css)); - assert(css.includes('.quotes')); - assert(/url\("?data:image\/gif;base64,no-quote"?\)/.test(css)); - assert(css.includes('.no-quote')); - - assert( - await outputFS.exists( - path.join(distDir, css.match(/url\((test\.[0-9a-f]+\.woff2)\)/)[1]), - ), - ); - }); - - it('should support linking to assets in parent folders with url() from CSS', async function () { - let b = await bundle( - [ - path.join( - __dirname, - '/integration/css-url-relative/src/a/style1.css', - ), - path.join( - __dirname, - '/integration/css-url-relative/src/b/style2.css', - ), - ], - { - defaultTargetOptions: { - shouldOptimize: true, - sourceMaps: false, - }, - }, - ); + assertBundles(b, [ + { + name: 'index.js', + assets: ['index.js', 'local.js'], + }, + { + name: 'index.css', + assets: ['index.css', 'local.css'], + }, + ]); - assertBundles(b, [ - { - type: 'css', - assets: ['style1.css'], - }, - { - type: 'css', - assets: ['style2.css'], - }, - { - type: 'png', - assets: ['foo.png'], - }, - ]); + let output = await run(b); + assert.equal(typeof output, 'function'); + assert.equal(output(), 3); + }); - let cssPath = path.join(distDir, 'a', 'style1.css'); - let css = await outputFS.readFile(cssPath, 'utf8'); + it('should bundle css dependencies in the correct, postorder traversal order', async () => { + let b = await bundle(path.join(__dirname, '/integration/css-order/a.css')); + + // Given a tree of css with imports: + // A + // / \ + // B E + // / \ + // C D + // + // (A imports B (which imports C and D) and E) + // + // ...styles should be applied in the order C, D, B, E, A + + assertBundles(b, [ + { + name: 'a.css', + assets: ['a.css', 'b.css', 'c.css', 'd.css', 'e.css'], + }, + ]); + + let css = await outputFS.readFile(path.join(distDir, 'a.css'), 'utf8'); + assert.ok( + css.indexOf('.c {') < css.indexOf('.d {') && + css.indexOf('.d {') < css.indexOf('.b {') && + css.indexOf('.b {') < css.indexOf('.e {') && + css.indexOf('.e {') < css.indexOf('.a {'), + ); + }); - assert(css.includes('background-image'), 'includes `background-image`'); - assert(/url\([^)]*\)/.test(css), 'includes url()'); + it('should support loading a CSS bundle along side dynamic imports', async () => { + let b = await bundle( + path.join(__dirname, '/integration/dynamic-css/index.js'), + ); - assert( - await outputFS.exists( - path.resolve(path.dirname(cssPath), css.match(/url\(([^)]*)\)/)[1]), - ), - 'path specified in url() exists', - ); - }); + assertBundles(b, [ + { + name: 'index.js', + assets: [ + 'bundle-url.js', + 'cacheLoader.js', + 'css-loader.js', + 'index.js', + 'js-loader.js', + ], + }, + {name: /local\.[0-9a-f]{8}\.js/, assets: ['local.js']}, + {name: /local\.[0-9a-f]{8}\.css/, assets: ['local.css']}, + {name: 'index.css', assets: ['index.css']}, + ]); + + let output = await run(b); + assert.equal(typeof output, 'function'); + assert.equal(await output(), 3); + }); - it('should ignore url() with IE behavior specifiers', async function () { - let b = await bundle( - path.join(__dirname, '/integration/css-url-behavior/index.css'), - ); + it('should support importing CSS from a CSS file', async function () { + let b = await bundle( + path.join(__dirname, '/integration/css-import/index.js'), + ); - assertBundles(b, [ - { - name: 'index.css', - assets: ['index.css'], - }, - ]); + assertBundles(b, [ + { + name: 'index.js', + assets: ['index.js'], + }, + { + name: 'index.css', + assets: ['index.css', 'other.css', 'local.css'], + }, + ]); - let css = await outputFS.readFile( - path.join(distDir, 'index.css'), - 'utf8', - ); + let output = await run(b); + assert.equal(typeof output, 'function'); + assert.equal(output(), 2); - assert(css.includes('url(#default#VML)')); - }); + let css = await outputFS.readFile(path.join(distDir, '/index.css'), 'utf8'); + assert(css.includes('.local')); + assert(css.includes('.other')); + assert(/@media print {\s*.other/.test(css)); + assert(css.includes('.index')); + }); - it('should minify CSS when minify is set', async function () { - let b = await bundle( - path.join(__dirname, '/integration/cssnano/index.js'), - { - defaultTargetOptions: { - shouldOptimize: true, - sourceMaps: false, - }, - }, - ); + it('should support linking to assets with url() from CSS', async function () { + let b = await bundle(path.join(__dirname, '/integration/css-url/index.js')); - let output = await run(b); - assert.equal(typeof output, 'function'); - assert.equal(output(), 3); + assertBundles(b, [ + { + name: 'index.js', + assets: ['index.js'], + }, + { + name: 'index.css', + assets: ['index.css'], + }, + { + type: 'woff2', + assets: ['test.woff2'], + }, + ]); + + let output = await run(b); + assert.equal(typeof output, 'function'); + assert.equal(output(), 2); + + let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8'); + assert(/url\("test\.[0-9a-f]+\.woff2"\)/.test(css)); + assert(css.includes('url("http://google.com")')); + assert(css.includes('.index')); + assert(css.includes('url("data:image/gif;base64,quotes")')); + assert(css.includes('.quotes')); + assert(css.includes('url("data:image/gif;base64,no-quote")')); + assert(css.includes('.no-quote')); + + assert( + await outputFS.exists( + path.join(distDir, css.match(/url\("(test\.[0-9a-f]+\.woff2)"\)/)[1]), + ), + ); + }); - let css = await outputFS.readFile( - path.join(distDir, 'index.css'), - 'utf8', - ); - assert(css.includes('.local')); - assert(css.includes('.index')); + it('should support linking to assets with url() from CSS in production', async function () { + let b = await bundle( + path.join(__dirname, '/integration/css-url/index.js'), + { + defaultTargetOptions: { + shouldOptimize: true, + }, + }, + ); - assert.equal(css.split('\n').length, 1); - }); + assertBundles(b, [ + { + name: 'index.js', + assets: ['index.js'], + }, + { + name: 'index.css', + assets: ['index.css'], + }, + { + type: 'woff2', + assets: ['test.woff2'], + }, + ]); + + let output = await run(b); + assert.equal(typeof output, 'function'); + assert.equal(output(), 2); + + let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8'); + assert(/url\(test\.[0-9a-f]+\.woff2\)/.test(css), 'woff ext found in css'); + assert(css.includes('url(http://google.com)'), 'url() found'); + assert(css.includes('.index'), '.index found'); + assert(/url\("?data:image\/gif;base64,quotes"?\)/.test(css)); + assert(css.includes('.quotes')); + assert(/url\("?data:image\/gif;base64,no-quote"?\)/.test(css)); + assert(css.includes('.no-quote')); + + assert( + await outputFS.exists( + path.join(distDir, css.match(/url\((test\.[0-9a-f]+\.woff2)\)/)[1]), + ), + ); + }); - it('should produce a sourcemap when sourceMaps are used', async function () { - await bundle(path.join(__dirname, '/integration/cssnano/index.js'), { - defaultTargetOptions: { - shouldOptimize: true, - }, - }); - - let css = await outputFS.readFile( - path.join(distDir, 'index.css'), - 'utf8', - ); - assert(css.includes('.local')); - assert(css.includes('.index')); - - let lines = css.trim().split('\n'); - assert.equal(lines.length, 2); - assert.equal(lines[1], '/*# sourceMappingURL=index.css.map */'); - - let map = JSON.parse( - await outputFS.readFile(path.join(distDir, 'index.css.map'), 'utf8'), - ); - assert.equal(map.file, 'index.css.map'); - assert(map.sources.includes('integration/cssnano/local.css')); - assert(map.sources.includes('integration/cssnano/index.css')); - }); - - it('should inline data-urls for text-encoded files', async () => { - await bundle(path.join(__dirname, '/integration/data-url/text.css'), { - defaultTargetOptions: { - sourceMaps: false, - }, - }); - let css = await outputFS.readFile( - path.join(distDir, 'text.css'), - 'utf8', - ); - assert.equal( - css.trim(), - `.svg-img { + it('should support linking to assets in parent folders with url() from CSS', async function () { + let b = await bundle( + [ + path.join(__dirname, '/integration/css-url-relative/src/a/style1.css'), + path.join(__dirname, '/integration/css-url-relative/src/b/style2.css'), + ], + { + defaultTargetOptions: { + shouldOptimize: true, + sourceMaps: false, + }, + }, + ); + + assertBundles(b, [ + { + type: 'css', + assets: ['style1.css'], + }, + { + type: 'css', + assets: ['style2.css'], + }, + { + type: 'png', + assets: ['foo.png'], + }, + ]); + + let cssPath = path.join(distDir, 'a', 'style1.css'); + let css = await outputFS.readFile(cssPath, 'utf8'); + + assert(css.includes('background-image'), 'includes `background-image`'); + assert(/url\([^)]*\)/.test(css), 'includes url()'); + + assert( + await outputFS.exists( + path.resolve(path.dirname(cssPath), css.match(/url\(([^)]*)\)/)[1]), + ), + 'path specified in url() exists', + ); + }); + + it('should ignore url() with IE behavior specifiers', async function () { + let b = await bundle( + path.join(__dirname, '/integration/css-url-behavior/index.css'), + ); + + assertBundles(b, [ + { + name: 'index.css', + assets: ['index.css'], + }, + ]); + + let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8'); + + assert(css.includes('url(#default#VML)')); + }); + + it('should minify CSS when minify is set', async function () { + let b = await bundle( + path.join(__dirname, '/integration/cssnano/index.js'), + { + defaultTargetOptions: { + shouldOptimize: true, + sourceMaps: false, + }, + }, + ); + + let output = await run(b); + assert.equal(typeof output, 'function'); + assert.equal(output(), 3); + + let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8'); + assert(css.includes('.local')); + assert(css.includes('.index')); + + assert.equal(css.split('\n').length, 1); + }); + + it('should produce a sourcemap when sourceMaps are used', async function () { + await bundle(path.join(__dirname, '/integration/cssnano/index.js'), { + defaultTargetOptions: { + shouldOptimize: true, + }, + }); + + let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8'); + assert(css.includes('.local')); + assert(css.includes('.index')); + + let lines = css.trim().split('\n'); + assert.equal(lines.length, 2); + assert.equal(lines[1], '/*# sourceMappingURL=index.css.map */'); + + let map = JSON.parse( + await outputFS.readFile(path.join(distDir, 'index.css.map'), 'utf8'), + ); + assert.equal(map.file, 'index.css.map'); + assert(map.sources.includes('integration/cssnano/local.css')); + assert(map.sources.includes('integration/cssnano/index.css')); + }); + + it('should inline data-urls for text-encoded files', async () => { + await bundle(path.join(__dirname, '/integration/data-url/text.css'), { + defaultTargetOptions: { + sourceMaps: false, + }, + }); + let css = await outputFS.readFile(path.join(distDir, 'text.css'), 'utf8'); + assert.equal( + css.trim(), + `.svg-img { 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"); }`, - ); - }); - - it('should inline data-urls for binary files', async () => { - await bundle(path.join(__dirname, '/integration/data-url/binary.css')); - let css = await outputFS.readFile( - path.join(distDir, 'binary.css'), - 'utf8', - ); - assert( - css.startsWith(`.webp-img { + ); + }); + + it('should inline data-urls for binary files', async () => { + await bundle(path.join(__dirname, '/integration/data-url/binary.css')); + let css = await outputFS.readFile(path.join(distDir, 'binary.css'), 'utf8'); + assert( + css.startsWith(`.webp-img { background-image: url("data:image/webp;base64,UklGR`), - ); - }); - - it('should remap locations in diagnostics using the input source map', async () => { - let fixture = path.join( - __dirname, - 'integration/diagnostic-sourcemap/index.scss', - ); - let code = await inputFS.readFileSync(fixture, 'utf8'); - // $FlowFixMe - await assert.rejects( - () => - bundle(fixture, { - defaultTargetOptions: { - shouldOptimize: true, - }, - }), + ); + }); + + it('should remap locations in diagnostics using the input source map', async () => { + let fixture = path.join( + __dirname, + 'integration/diagnostic-sourcemap/index.scss', + ); + let code = await inputFS.readFileSync(fixture, 'utf8'); + // $FlowFixMe + await assert.rejects( + () => + bundle(fixture, { + defaultTargetOptions: { + shouldOptimize: true, + }, + }), + { + name: 'BuildError', + diagnostics: [ { - name: 'BuildError', - diagnostics: [ + message: "Failed to resolve 'x.png' from './index.scss'", + origin: '@parcel/core', + codeFrames: [ { - message: "Failed to resolve 'x.png' from './index.scss'", - origin: '@parcel/core', - codeFrames: [ + filePath: fixture, + code, + codeHighlights: [ { - filePath: fixture, - code, - codeHighlights: [ - { - start: { - line: 5, - column: 3, - }, - end: { - line: 5, - column: 3, - }, - }, - ], + start: { + line: 5, + column: 3, + }, + end: { + line: 5, + column: 3, + }, }, ], }, - { - message: "Cannot load file './x.png' in './'.", - origin: '@parcel/resolver-default', - hints: [], - }, ], }, - ); - }); - - 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'], + message: "Cannot load file './x.png' in './'.", + origin: '@parcel/resolver-default', + hints: [], }, - ]); - }); + ], + }, + ); + }); - it('should support external CSS imports', async () => { - let b = await bundle( - path.join(__dirname, '/integration/css-external/a.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: 'a.css', - assets: ['a.css', 'b.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( - new RegExp(`@import "http://example.com/external.css"; + let res = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8'); + assert( + new RegExp(`@import "http://example.com/external.css"; .b { color: red; }\n? .a { color: green; }`).test(res), - ); - }); - }); - } + ); + }); it('should support css nesting with @parcel/css', async function () { - let b = await originalBundle( + let b = await bundle( path.join(__dirname, '/integration/css-nesting/a.css'), { - defaultConfig: - path.dirname(require.resolve('@parcel/test-utils')) + - '/.parcelrc-css', defaultTargetOptions: { engines: {}, }, diff --git a/packages/core/test-utils/src/.parcelrc-css b/packages/core/test-utils/src/.parcelrc-css deleted file mode 100644 index 1d8a4120038..00000000000 --- a/packages/core/test-utils/src/.parcelrc-css +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "@parcel/config-default", - "transformers": { - "*.css": ["@parcel/transformer-postcss", "@parcel/transformer-css-experimental"] - }, - "optimizers": { - "*.css": ["@parcel/optimizer-css"] - }, - "reporters": [] -} diff --git a/packages/optimizers/css/package.json b/packages/optimizers/css/package.json index 183963682a3..873bf247fd1 100644 --- a/packages/optimizers/css/package.json +++ b/packages/optimizers/css/package.json @@ -20,7 +20,8 @@ "parcel": "^2.3.2" }, "dependencies": { - "@parcel/css": "^1.0.3", + "@parcel/css": "^1.6.0", + "@parcel/diagnostic": "2.3.2", "@parcel/plugin": "2.3.2", "@parcel/source-map": "^2.0.0", "@parcel/utils": "2.3.2", diff --git a/packages/optimizers/css/src/CSSOptimizer.js b/packages/optimizers/css/src/CSSOptimizer.js index d6b415eb2c6..7e4507a609a 100644 --- a/packages/optimizers/css/src/CSSOptimizer.js +++ b/packages/optimizers/css/src/CSSOptimizer.js @@ -10,8 +10,54 @@ import { import {blobToBuffer} from '@parcel/utils'; import browserslist from 'browserslist'; import nullthrows from 'nullthrows'; +import path from 'path'; +import {md, generateJSONCodeHighlights} from '@parcel/diagnostic'; export default (new Optimizer({ + async loadConfig({config, logger, options}) { + const configFile = await config.getConfig( + ['.cssnanorc', 'cssnano.config.json', 'cssnano.config.js'], + { + packageKey: 'cssnano', + }, + ); + if (configFile) { + let filename = path.basename(configFile.filePath); + let codeHighlights; + let message; + if (filename === 'package.json') { + message = md` +Parcel\'s default CSS minifer changed from cssnano to @parcel/css, but a "cssnano" key was found in **package.json**. Either remove this configuration, or configure Parcel to use @parcel/optimizer-cssnano instead. + `; + let contents = await options.inputFS.readFile( + configFile.filePath, + 'utf8', + ); + codeHighlights = generateJSONCodeHighlights(contents, [ + {key: '/cssnano', type: 'key'}, + ]); + } else { + message = md`Parcel\'s default CSS minifer changed from cssnano to @parcel/css, but a __${filename}__ config file was found. Either remove this config file, or configure Parcel to use @parcel/optimizer-cssnano instead.`; + codeHighlights = [ + { + start: {line: 1, column: 1}, + end: {line: 1, column: 1}, + }, + ]; + } + + logger.warn({ + message, + documentationURL: 'https://parceljs.org/languages/css/#minification', + codeFrames: [ + { + filePath: configFile.filePath, + codeHighlights, + }, + ], + }); + } + }, async optimize({ bundle, bundleGraph, diff --git a/packages/transformers/css-experimental/package.json b/packages/transformers/css-experimental/package.json deleted file mode 100644 index 13594a55d33..00000000000 --- a/packages/transformers/css-experimental/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "@parcel/transformer-css-experimental", - "version": "2.3.2", - "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/CSSTransformer.js", - "source": "src/CSSTransformer.js", - "engines": { - "node": ">= 12.0.0", - "parcel": "^2.3.2" - }, - "dependencies": { - "@parcel/css": "^1.0.3", - "@parcel/plugin": "2.3.2", - "@parcel/source-map": "^2.0.0", - "@parcel/utils": "2.3.2", - "browserslist": "^4.6.6", - "nullthrows": "^1.1.1" - } -} diff --git a/packages/transformers/css-experimental/src/CSSTransformer.js b/packages/transformers/css-experimental/src/CSSTransformer.js deleted file mode 100644 index 58f1638f331..00000000000 --- a/packages/transformers/css-experimental/src/CSSTransformer.js +++ /dev/null @@ -1,232 +0,0 @@ -// @flow strict-local - -import path from 'path'; -import SourceMap from '@parcel/source-map'; -import {Transformer} from '@parcel/plugin'; -import { - transform, - transformStyleAttribute, - browserslistToTargets, -} from '@parcel/css'; -import {remapSourceLocation} from '@parcel/utils'; -import browserslist from 'browserslist'; -import nullthrows from 'nullthrows'; - -export default (new Transformer({ - async loadConfig({config, options}) { - let conf = await config.getConfigFrom(options.projectRoot + '/index', [], { - packageKey: '@parcel/transformer-css', - }); - return conf?.contents; - }, - async transform({asset, config, options}) { - let [code, originalMap] = await Promise.all([ - asset.getBuffer(), - asset.getMap(), - ]); - - let targets = getTargets(asset.env.engines.browsers); - let res; - if (asset.meta.type === 'attr') { - res = transformStyleAttribute({ - code, - analyzeDependencies: true, - targets, - }); - } else { - res = transform({ - filename: path.relative(options.projectRoot, asset.filePath), - code, - cssModules: - config?.cssModules ?? - (asset.meta.cssModulesCompiled !== true && - /\.module\./.test(asset.filePath)), - analyzeDependencies: asset.meta.hasDependencies !== false, - sourceMap: !!asset.env.sourceMap, - drafts: config?.drafts, - pseudoClasses: config?.pseudoClasses, - targets, - }); - } - - asset.setBuffer(res.code); - - if (res.map != null) { - let vlqMap = JSON.parse(res.map.toString()); - let map = new SourceMap(options.projectRoot); - map.addVLQMap(vlqMap); - - if (originalMap) { - map.extends(originalMap); - } - - asset.setMap(map); - } - - if (res.dependencies) { - for (let dep of res.dependencies) { - let loc = dep.loc; - if (originalMap) { - loc = remapSourceLocation(loc, originalMap); - } - - if (dep.type === 'import') { - asset.addDependency({ - specifier: dep.url, - specifierType: 'url', - loc, - meta: { - // For the glob resolver to distinguish between `@import` and other URL dependencies. - isCSSImport: true, - media: dep.media, - }, - symbols: new Map([['*', {local: '*', isWeak: true, loc}]]), - }); - } else if (dep.type === 'url') { - asset.addURLDependency(dep.url, { - loc, - meta: { - placeholder: dep.placeholder, - }, - }); - } - } - } - - let assets = [asset]; - - if (res.exports != null) { - let exports = res.exports; - asset.symbols.ensure(); - asset.symbols.set('default', 'default'); - - let dependencies = new Map(); - let selfReferences = new Set(); - let locals = new Map(); - let c = 0; - let depjs = ''; - let js = ''; - - let jsDeps = []; - for (let dep of asset.getDependencies()) { - if (dep.priority === 'sync') { - // TODO: Figure out how to treeshake this - let d = `dep_$${c++}`; - depjs += `import * as ${d} from ${JSON.stringify(dep.specifier)};\n`; - depjs += `for (let key in ${d}) { if (key in module.exports) module.exports[key] += ' ' + ${d}[key]; else module.exports[key] = ${d}[key]; }\n`; - } - } - - for (let key in exports) { - locals.set(exports[key].name, key); - } - - let seen = new Set(); - let add = key => { - if (seen.has(key)) { - return; - } - seen.add(key); - - let e = exports[key]; - let s = `module.exports[${JSON.stringify(key)}] = \`${e.name}`; - - if (e.isReferenced) { - selfReferences.add(e.name); - } - - for (let ref of e.composes) { - s += ' '; - if (ref.type === 'local') { - add(nullthrows(locals.get(ref.name))); - s += - '${' + - `module.exports[${JSON.stringify( - nullthrows(locals.get(ref.name)), - )}]` + - '}'; - } else if (ref.type === 'global') { - s += ref.name; - } else if (ref.type === 'dependency') { - let d = dependencies.get(ref.specifier); - if (d == null) { - d = `dep_${c++}`; - depjs += `import * as ${d} from ${JSON.stringify( - ref.specifier, - )};\n`; - dependencies.set(ref.specifier, d); - - asset.addDependency({ - specifier: ref.specifier, - specifierType: 'url', - }); - } - s += '${' + `${d}[${JSON.stringify(ref.name)}]` + '}'; - } - } - - s += '`;\n'; - js += s; - }; - - for (let key in exports) { - asset.symbols.set(key, exports[key].name); - add(key); - } - - assets.push({ - type: 'js', - content: depjs + js, - dependencies: jsDeps, - env: asset.env, - }); - - if (selfReferences.size > 0) { - asset.addDependency({ - specifier: `./${path.basename(asset.filePath)}`, - specifierType: 'url', - symbols: new Map( - [...locals] - .filter(([local]) => selfReferences.has(local)) - .map(([local, exported]) => [ - exported, - {local, isWeak: false, loc: null}, - ]), - ), - }); - } - } - - // Normalize the asset's environment so that properties that only affect JS don't cause CSS to be duplicated. - // For example, with ESModule and CommonJS targets, only a single shared CSS bundle should be produced. - asset.setEnvironment({ - context: 'browser', - engines: { - browsers: asset.env.engines.browsers, - }, - shouldOptimize: asset.env.shouldOptimize, - shouldScopeHoist: asset.env.shouldScopeHoist, - sourceMap: asset.env.sourceMap, - }); - - return assets; - }, -}): Transformer); - -let cache = new Map(); - -function getTargets(browsers) { - if (browsers == null) { - return undefined; - } - - let cached = cache.get(browsers); - if (cached != null) { - return cached; - } - - let targets = browserslistToTargets(browserslist(browsers)); - - cache.set(browsers, targets); - return targets; -} diff --git a/packages/transformers/css/package.json b/packages/transformers/css/package.json index f5c0e1e7e37..43ac3330841 100644 --- a/packages/transformers/css/package.json +++ b/packages/transformers/css/package.json @@ -20,16 +20,11 @@ "parcel": "^2.3.2" }, "dependencies": { - "@parcel/hash": "2.3.2", + "@parcel/css": "^1.6.0", "@parcel/plugin": "2.3.2", "@parcel/source-map": "^2.0.0", "@parcel/utils": "2.3.2", - "nullthrows": "^1.1.1", - "postcss": "^8.4.5", - "postcss-value-parser": "^4.2.0", - "semver": "^5.7.1" - }, - "devDependencies": { - "postcss-modules": "^4.3.0" + "browserslist": "^4.6.6", + "nullthrows": "^1.1.1" } } diff --git a/packages/transformers/css/src/CSSTransformer.js b/packages/transformers/css/src/CSSTransformer.js index 8aff146b660..58f1638f331 100644 --- a/packages/transformers/css/src/CSSTransformer.js +++ b/packages/transformers/css/src/CSSTransformer.js @@ -1,376 +1,232 @@ -// @flow +// @flow strict-local -import type {Root} from 'postcss'; -import type {FilePath, MutableAsset, PluginOptions} from '@parcel/types'; - -import {hashString} from '@parcel/hash'; +import path from 'path'; import SourceMap from '@parcel/source-map'; import {Transformer} from '@parcel/plugin'; -import {createDependencyLocation, remapSourceLocation} from '@parcel/utils'; -import postcss from 'postcss'; +import { + transform, + transformStyleAttribute, + browserslistToTargets, +} from '@parcel/css'; +import {remapSourceLocation} from '@parcel/utils'; +import browserslist from 'browserslist'; import nullthrows from 'nullthrows'; -import valueParser from 'postcss-value-parser'; -import semver from 'semver'; -import path from 'path'; - -const URL_RE = /url\s*\(/; -const IMPORT_RE = /@import/; -const COMPOSES_RE = /composes:.+from\s*("|').*("|')\s*;?/; -const FROM_IMPORT_RE = /.+from\s*(?:"|')(.*)(?:"|')\s*;?/; -const MODULE_BY_NAME_RE = /\.module\./; - -function canHaveDependencies(filePath: FilePath, code: string) { - return !/\.css$/.test(filePath) || IMPORT_RE.test(code) || URL_RE.test(code); -} export default (new Transformer({ - canReuseAST({ast}) { - return ast.type === 'postcss' && semver.satisfies(ast.version, '^8.2.1'); + async loadConfig({config, options}) { + let conf = await config.getConfigFrom(options.projectRoot + '/index', [], { + packageKey: '@parcel/transformer-css', + }); + return conf?.contents; }, - - async parse({asset}) { - // This is set by other transformers (e.g. Stylus) to indicate that it has already processed - // all dependencies, and that the CSS transformer can skip this asset completely. This is - // required because when stylus processes e.g. url() it replaces them with a dependency id - // to be filled in later. When the CSS transformer runs, it would pick that up and try to - // resolve a dependency for the id which obviously doesn't exist. Also, it's faster to do - // it this way since the resulting CSS doesn't need to be re-parsed. - let isCSSModule = - asset.meta.cssModulesCompiled !== true && - MODULE_BY_NAME_RE.test(asset.filePath); - if (asset.meta.hasDependencies === false && !isCSSModule) { - return null; + async transform({asset, config, options}) { + let [code, originalMap] = await Promise.all([ + asset.getBuffer(), + asset.getMap(), + ]); + + let targets = getTargets(asset.env.engines.browsers); + let res; + if (asset.meta.type === 'attr') { + res = transformStyleAttribute({ + code, + analyzeDependencies: true, + targets, + }); + } else { + res = transform({ + filename: path.relative(options.projectRoot, asset.filePath), + code, + cssModules: + config?.cssModules ?? + (asset.meta.cssModulesCompiled !== true && + /\.module\./.test(asset.filePath)), + analyzeDependencies: asset.meta.hasDependencies !== false, + sourceMap: !!asset.env.sourceMap, + drafts: config?.drafts, + pseudoClasses: config?.pseudoClasses, + targets, + }); } - let code = await asset.getCode(); - if ( - code != null && - !canHaveDependencies(asset.filePath, code) && - !isCSSModule - ) { - return null; - } + asset.setBuffer(res.code); - return { - type: 'postcss', - version: '8.2.1', - program: postcss - .parse(code, { - from: asset.filePath, - }) - .toJSON(), - }; - }, + if (res.map != null) { + let vlqMap = JSON.parse(res.map.toString()); + let map = new SourceMap(options.projectRoot); + map.addVLQMap(vlqMap); - async transform({asset, resolve, options}) { - // Normalize the asset's environment so that properties that only affect JS don't cause CSS to be duplicated. - // For example, with ESModule and CommonJS targets, only a single shared CSS bundle should be produced. - let env = asset.env; - asset.setEnvironment({ - context: 'browser', - engines: { - browsers: asset.env.engines.browsers, - }, - shouldOptimize: asset.env.shouldOptimize, - sourceMap: asset.env.sourceMap, - }); - - let isCSSModule = - asset.meta.cssModulesCompiled !== true && - MODULE_BY_NAME_RE.test(asset.filePath); + if (originalMap) { + map.extends(originalMap); + } - // Check for `hasDependencies` being false here as well, as it's possible - // another transformer (such as PostCSSTransformer) has already parsed an - // ast and CSSTransformer's parse was never called. - let ast = await asset.getAST(); - if (!ast || (asset.meta.hasDependencies === false && !isCSSModule)) { - return [asset]; + asset.setMap(map); } - let program: Root = postcss.fromJSON(ast.program); - let assets = [asset]; - if (isCSSModule) { - assets = await compileCSSModules(asset, env, program, resolve, options); - } + if (res.dependencies) { + for (let dep of res.dependencies) { + let loc = dep.loc; + if (originalMap) { + loc = remapSourceLocation(loc, originalMap); + } - if (asset.meta.hasDependencies === false) { - return assets; + if (dep.type === 'import') { + asset.addDependency({ + specifier: dep.url, + specifierType: 'url', + loc, + meta: { + // For the glob resolver to distinguish between `@import` and other URL dependencies. + isCSSImport: true, + media: dep.media, + }, + symbols: new Map([['*', {local: '*', isWeak: true, loc}]]), + }); + } else if (dep.type === 'url') { + asset.addURLDependency(dep.url, { + loc, + meta: { + placeholder: dep.placeholder, + }, + }); + } + } } - let originalSourceMap = await asset.getMap(); - let createLoc = (start, specifier, lineOffset, colOffset, o) => { - let loc = createDependencyLocation( - start, - specifier, - lineOffset, - colOffset, - o, - ); - if (originalSourceMap) { - loc = remapSourceLocation(loc, originalSourceMap); - } - return loc; - }; + let assets = [asset]; - let isDirty = false; - program.walkAtRules('import', rule => { - let params = valueParser(rule.params); - let [name, ...media] = params.nodes; - let specifier; - if ( - name.type === 'function' && - name.value === 'url' && - name.nodes.length - ) { - name = name.nodes[0]; + if (res.exports != null) { + let exports = res.exports; + asset.symbols.ensure(); + asset.symbols.set('default', 'default'); + + let dependencies = new Map(); + let selfReferences = new Set(); + let locals = new Map(); + let c = 0; + let depjs = ''; + let js = ''; + + let jsDeps = []; + for (let dep of asset.getDependencies()) { + if (dep.priority === 'sync') { + // TODO: Figure out how to treeshake this + let d = `dep_$${c++}`; + depjs += `import * as ${d} from ${JSON.stringify(dep.specifier)};\n`; + depjs += `for (let key in ${d}) { if (key in module.exports) module.exports[key] += ' ' + ${d}[key]; else module.exports[key] = ${d}[key]; }\n`; + } } - specifier = name.value; - - if (!specifier) { - throw new Error('Could not find import name for ' + String(rule)); + for (let key in exports) { + locals.set(exports[key].name, key); } - // If this came from an inline