diff --git a/CHANGELOG.md b/CHANGELOG.md index 92dbcf0f606..d1f0b398684 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,32 @@ All notable changes to Parcel will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and Parcel adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [2.4.0] - 2022-03-22 + +## Added + +- Replace default CSS transformer and minifier with `@parcel/css` - [Details](https://github.com/parcel-bundler/parcel/pull/7821) +- Replace `typeof` before dead code elimination to improve bundle size - [Details](https://github.com/parcel-bundler/parcel/pull/7788) +- Human readable file size in bundle analyzer report - [Details](https://github.com/parcel-bundler/parcel/pull/7766) +- Improve emoji support detection - [Details](https://github.com/parcel-bundler/parcel/pull/7775) +- Enable parsing static class initialization blocks - [Details](https://github.com/parcel-bundler/parcel/pull/7839) +- Use `PORT` environment variable from `.env` files - [Details](https://github.com/parcel-bundler/parcel/pull/7819) +- Use new react-jsx transform in React 16.14.0 - [Details](https://github.com/parcel-bundler/parcel/pull/7728) +- Use relative path for bundle labels in bundle analysis - [Details](https://github.com/parcel-bundler/parcel/pull/7737) +- Load dynamic imports at higher network priority in non-ESM builds - [Details](https://github.com/parcel-bundler/parcel/pull/7061) + +## Fixed + +- Pin lmdb to 2.2.3 - [Details](https://github.com/parcel-bundler/parcel/pull/7763) +- Prevent term-size from being bundled - [Details](https://github.com/parcel-bundler/parcel/pull/7750) +- Fix cache when non-ascii chars are used in path - [Details](https://github.com/parcel-bundler/parcel/pull/7797) +- Bump SWC. Fixes issue with `String` constructor. - [Details](https://github.com/parcel-bundler/parcel/pull/7777) +- Fix DCE with PURE comments - [Details](https://github.com/parcel-bundler/parcel/pull/7833) +- Escape double quote of url value in CSS `url()` - [Details](https://github.com/parcel-bundler/parcel/pull/7718) +- Fix documentation comment in API - [Details](https://github.com/parcel-bundler/parcel/pull/7689) +- Fix package.json `source` field resolution with pnpm - [Details](https://github.com/parcel-bundler/parcel/pull/7846) +- Fix `errors.map is not a function` - [Details](https://github.com/parcel-bundler/parcel/pull/7672) + ## [2.3.1] - 2022-02-09 ## Fixed 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/bundlers/default/package.json b/packages/bundlers/default/package.json index c556d0061b2..296b6adfa4b 100644 --- a/packages/bundlers/default/package.json +++ b/packages/bundlers/default/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/bundler-default", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,13 +17,13 @@ "source": "src/DefaultBundler.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/diagnostic": "2.3.2", - "@parcel/hash": "2.3.2", - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/hash": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", "nullthrows": "^1.1.1" } } diff --git a/packages/bundlers/experimental/package.json b/packages/bundlers/experimental/package.json index 0edad2dbef0..de34c89423b 100644 --- a/packages/bundlers/experimental/package.json +++ b/packages/bundlers/experimental/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/bundler-experimental", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,14 +17,14 @@ "source": "src/ExperimentalBundler.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/diagnostic": "2.3.2", - "@parcel/graph": "2.3.2", - "@parcel/hash": "2.3.2", - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/graph": "2.4.0", + "@parcel/hash": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", "nullthrows": "^1.1.1" } } diff --git a/packages/compressors/brotli/package.json b/packages/compressors/brotli/package.json index aa11b4c7e96..7ecd9be4b62 100644 --- a/packages/compressors/brotli/package.json +++ b/packages/compressors/brotli/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/compressor-brotli", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,9 +17,9 @@ "source": "src/BrotliCompressor.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2" + "@parcel/plugin": "2.4.0" } } diff --git a/packages/compressors/gzip/package.json b/packages/compressors/gzip/package.json index 7abd22b86d3..3b895fe8985 100644 --- a/packages/compressors/gzip/package.json +++ b/packages/compressors/gzip/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/compressor-gzip", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,9 +17,9 @@ "source": "src/GzipCompressor.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2" + "@parcel/plugin": "2.4.0" } } diff --git a/packages/compressors/raw/package.json b/packages/compressors/raw/package.json index e2e40e90f25..9602e3381d8 100644 --- a/packages/compressors/raw/package.json +++ b/packages/compressors/raw/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/compressor-raw", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,9 +17,9 @@ "source": "src/RawCompressor.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2" + "@parcel/plugin": "2.4.0" } } 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..7c672453c06 100644 --- a/packages/configs/default/package.json +++ b/packages/configs/default/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/config-default", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -18,63 +18,63 @@ "test-ci": "mocha" }, "dependencies": { - "@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-htmlnano": "2.3.2", - "@parcel/optimizer-image": "2.3.2", - "@parcel/optimizer-svgo": "2.3.2", - "@parcel/optimizer-terser": "2.3.2", - "@parcel/packager-css": "2.3.2", - "@parcel/packager-html": "2.3.2", - "@parcel/packager-js": "2.3.2", - "@parcel/packager-raw": "2.3.2", - "@parcel/packager-svg": "2.3.2", - "@parcel/reporter-dev-server": "2.3.2", - "@parcel/resolver-default": "2.3.2", - "@parcel/runtime-browser-hmr": "2.3.2", - "@parcel/runtime-js": "2.3.2", - "@parcel/runtime-react-refresh": "2.3.2", - "@parcel/runtime-service-worker": "2.3.2", - "@parcel/transformer-babel": "2.3.2", - "@parcel/transformer-css": "2.3.2", - "@parcel/transformer-html": "2.3.2", - "@parcel/transformer-image": "2.3.2", - "@parcel/transformer-js": "2.3.2", - "@parcel/transformer-json": "2.3.2", - "@parcel/transformer-postcss": "2.3.2", - "@parcel/transformer-posthtml": "2.3.2", - "@parcel/transformer-raw": "2.3.2", - "@parcel/transformer-react-refresh-wrap": "2.3.2", - "@parcel/transformer-svg": "2.3.2" + "@parcel/bundler-default": "2.4.0", + "@parcel/compressor-raw": "2.4.0", + "@parcel/namer-default": "2.4.0", + "@parcel/optimizer-css": "2.4.0", + "@parcel/optimizer-htmlnano": "2.4.0", + "@parcel/optimizer-image": "2.4.0", + "@parcel/optimizer-svgo": "2.4.0", + "@parcel/optimizer-terser": "2.4.0", + "@parcel/packager-css": "2.4.0", + "@parcel/packager-html": "2.4.0", + "@parcel/packager-js": "2.4.0", + "@parcel/packager-raw": "2.4.0", + "@parcel/packager-svg": "2.4.0", + "@parcel/reporter-dev-server": "2.4.0", + "@parcel/resolver-default": "2.4.0", + "@parcel/runtime-browser-hmr": "2.4.0", + "@parcel/runtime-js": "2.4.0", + "@parcel/runtime-react-refresh": "2.4.0", + "@parcel/runtime-service-worker": "2.4.0", + "@parcel/transformer-babel": "2.4.0", + "@parcel/transformer-css": "2.4.0", + "@parcel/transformer-html": "2.4.0", + "@parcel/transformer-image": "2.4.0", + "@parcel/transformer-js": "2.4.0", + "@parcel/transformer-json": "2.4.0", + "@parcel/transformer-postcss": "2.4.0", + "@parcel/transformer-posthtml": "2.4.0", + "@parcel/transformer-raw": "2.4.0", + "@parcel/transformer-react-refresh-wrap": "2.4.0", + "@parcel/transformer-svg": "2.4.0" }, "parcelDependencies": { - "@parcel/optimizer-data-url": "2.3.2", - "@parcel/packager-raw-url": "2.3.2", - "@parcel/packager-ts": "2.3.2", - "@parcel/packager-xml": "2.3.2", - "@parcel/transformer-coffeescript": "2.3.2", - "@parcel/transformer-elm": "2.3.2", - "@parcel/transformer-glsl": "2.3.2", - "@parcel/transformer-graphql": "2.3.2", - "@parcel/transformer-inline-string": "2.3.2", - "@parcel/transformer-jsonld": "2.3.2", - "@parcel/transformer-less": "2.3.2", - "@parcel/transformer-mdx": "2.3.2", - "@parcel/transformer-pug": "2.3.2", - "@parcel/transformer-sass": "2.3.2", - "@parcel/transformer-stylus": "2.3.2", - "@parcel/transformer-sugarss": "2.3.2", - "@parcel/transformer-toml": "2.3.2", - "@parcel/transformer-typescript-types": "2.3.2", - "@parcel/transformer-vue": "2.3.2", - "@parcel/transformer-webmanifest": "2.3.2", - "@parcel/transformer-worklet": "2.3.2", - "@parcel/transformer-xml": "2.3.2", - "@parcel/transformer-yaml": "2.3.2" + "@parcel/optimizer-data-url": "2.4.0", + "@parcel/packager-raw-url": "2.4.0", + "@parcel/packager-ts": "2.4.0", + "@parcel/packager-xml": "2.4.0", + "@parcel/transformer-coffeescript": "2.4.0", + "@parcel/transformer-elm": "2.4.0", + "@parcel/transformer-glsl": "2.4.0", + "@parcel/transformer-graphql": "2.4.0", + "@parcel/transformer-inline-string": "2.4.0", + "@parcel/transformer-jsonld": "2.4.0", + "@parcel/transformer-less": "2.4.0", + "@parcel/transformer-mdx": "2.4.0", + "@parcel/transformer-pug": "2.4.0", + "@parcel/transformer-sass": "2.4.0", + "@parcel/transformer-stylus": "2.4.0", + "@parcel/transformer-sugarss": "2.4.0", + "@parcel/transformer-toml": "2.4.0", + "@parcel/transformer-typescript-types": "2.4.0", + "@parcel/transformer-vue": "2.4.0", + "@parcel/transformer-webmanifest": "2.4.0", + "@parcel/transformer-worklet": "2.4.0", + "@parcel/transformer-xml": "2.4.0", + "@parcel/transformer-yaml": "2.4.0" }, "peerDependencies": { - "@parcel/core": "^2.3.2" + "@parcel/core": "^2.4.0" } } diff --git a/packages/configs/webextension/package.json b/packages/configs/webextension/package.json index 8d9174a4b5a..1459d727fdb 100644 --- a/packages/configs/webextension/package.json +++ b/packages/configs/webextension/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/config-webextension", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -15,9 +15,9 @@ }, "main": "index.json", "dependencies": { - "@parcel/config-default": "2.3.2", - "@parcel/packager-raw-url": "2.3.2", - "@parcel/transformer-raw": "2.3.2", - "@parcel/transformer-webextension": "2.3.2" + "@parcel/config-default": "2.4.0", + "@parcel/packager-raw-url": "2.4.0", + "@parcel/transformer-raw": "2.4.0", + "@parcel/transformer-webextension": "2.4.0" } } diff --git a/packages/core/cache/package.json b/packages/core/cache/package.json index 70181e28d46..5f228b5201b 100644 --- a/packages/core/cache/package.json +++ b/packages/core/cache/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/cache", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -24,13 +24,13 @@ "check-ts": "tsc --noEmit index.d.ts" }, "dependencies": { - "@parcel/fs": "2.3.2", - "@parcel/logger": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/fs": "2.4.0", + "@parcel/logger": "2.4.0", + "@parcel/utils": "2.4.0", "lmdb": "2.2.4" }, "peerDependencies": { - "@parcel/core": "^2.3.2" + "@parcel/core": "^2.4.0" }, "devDependencies": { "idb": "^5.0.8" diff --git a/packages/core/codeframe/package.json b/packages/core/codeframe/package.json index 568a2343c89..ae5f5743c3c 100644 --- a/packages/core/codeframe/package.json +++ b/packages/core/codeframe/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/codeframe", - "version": "2.3.2", + "version": "2.4.0", "description": "Blazing fast, zero configuration web application bundler", "license": "MIT", "publishConfig": { diff --git a/packages/core/core/package.json b/packages/core/core/package.json index a557477e13d..a16fdb27021 100644 --- a/packages/core/core/package.json +++ b/packages/core/core/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/core", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -24,19 +24,19 @@ "check-ts": "tsc --noEmit index.d.ts" }, "dependencies": { - "@parcel/cache": "2.3.2", - "@parcel/diagnostic": "2.3.2", - "@parcel/events": "2.3.2", - "@parcel/fs": "2.3.2", - "@parcel/graph": "2.3.2", - "@parcel/hash": "2.3.2", - "@parcel/logger": "2.3.2", - "@parcel/package-manager": "2.3.2", - "@parcel/plugin": "2.3.2", + "@parcel/cache": "2.4.0", + "@parcel/diagnostic": "2.4.0", + "@parcel/events": "2.4.0", + "@parcel/fs": "2.4.0", + "@parcel/graph": "2.4.0", + "@parcel/hash": "2.4.0", + "@parcel/logger": "2.4.0", + "@parcel/package-manager": "2.4.0", + "@parcel/plugin": "2.4.0", "@parcel/source-map": "^2.0.0", - "@parcel/types": "2.3.2", - "@parcel/utils": "2.3.2", - "@parcel/workers": "2.3.2", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", + "@parcel/workers": "2.4.0", "abortcontroller-polyfill": "^1.1.9", "base-x": "^3.0.8", "browserslist": "^4.6.6", 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; +} diff --git a/packages/core/diagnostic/package.json b/packages/core/diagnostic/package.json index fd4babbee4a..e5686306930 100644 --- a/packages/core/diagnostic/package.json +++ b/packages/core/diagnostic/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/diagnostic", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" diff --git a/packages/core/fs/package.json b/packages/core/fs/package.json index fc6dd93454a..93edb83d025 100644 --- a/packages/core/fs/package.json +++ b/packages/core/fs/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/fs", - "version": "2.3.2", + "version": "2.4.0", "description": "Blazing fast, zero configuration web application bundler", "license": "MIT", "publishConfig": { @@ -48,21 +48,21 @@ "check-ts": "tsc --noEmit index.d.ts" }, "dependencies": { - "@parcel/fs-search": "2.3.2", - "@parcel/types": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/fs-search": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", "@parcel/watcher": "^2.0.0", - "@parcel/workers": "2.3.2" + "@parcel/workers": "2.4.0" }, "devDependencies": { - "@parcel/fs-write-stream-atomic": "2.3.2", + "@parcel/fs-write-stream-atomic": "2.4.0", "graceful-fs": "^4.2.4", "ncp": "^2.0.0", "nullthrows": "^1.1.1", "utility-types": "^3.10.0" }, "peerDependencies": { - "@parcel/core": "^2.3.2" + "@parcel/core": "^2.4.0" }, "browser": { "@parcel/fs": "./lib/browser.js", diff --git a/packages/core/graph/package.json b/packages/core/graph/package.json index 4218ce9c205..2736bf3d924 100644 --- a/packages/core/graph/package.json +++ b/packages/core/graph/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/graph", - "version": "2.3.2", + "version": "2.4.0", "description": "Blazing fast, zero configuration web application bundler", "license": "MIT", "publishConfig": { @@ -20,7 +20,7 @@ "node": ">= 12.0.0" }, "dependencies": { - "@parcel/utils": "2.3.2", + "@parcel/utils": "2.4.0", "nullthrows": "^1.1.1" } } diff --git a/packages/core/integration-tests/package.json b/packages/core/integration-tests/package.json index e62fa6fbc0a..b2f718f0014 100644 --- a/packages/core/integration-tests/package.json +++ b/packages/core/integration-tests/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/integration-tests", - "version": "2.3.2", + "version": "2.4.0", "private": true, "license": "MIT", "repository": { @@ -42,7 +42,7 @@ "ncp": "^2.0.0", "nib": "^1.1.2", "node-elm-compiler": "^5.0.5", - "parcel": "2.3.2", + "parcel": "2.4.0", "postcss": "^8.4.5", "postcss-custom-properties": "^12.1.2", "postcss-import": "^14.0.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..128a08c1619 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,473 @@ 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); + }); + + 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 {'), + ); + }); - let cssPath = path.join(distDir, 'a', 'style1.css'); - let css = await outputFS.readFile(cssPath, 'utf8'); + 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(css.includes('background-image'), 'includes `background-image`'); - assert(/url\([^)]*\)/.test(css), 'includes url()'); + 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); + }); - assert( - await outputFS.exists( - path.resolve(path.dirname(cssPath), css.match(/url\(([^)]*)\)/)[1]), - ), - 'path specified in url() exists', - ); - }); + it('should support importing CSS from a CSS file', async function () { + let b = await bundle( + path.join(__dirname, '/integration/css-import/index.js'), + ); - 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.js', + assets: ['index.js'], + }, + { + name: 'index.css', + assets: ['index.css', 'other.css', 'local.css'], + }, + ]); - assertBundles(b, [ - { - name: 'index.css', - assets: ['index.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', - ); + 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')); + }); - assert(css.includes('url(#default#VML)')); - }); + it('should support linking to assets with url() from CSS', async function () { + let b = await bundle(path.join(__dirname, '/integration/css-url/index.js')); - 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, - }, - }, - ); + 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 output = await run(b); - assert.equal(typeof output, 'function'); - assert.equal(output(), 3); + 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, + }, + }, + ); - let css = await outputFS.readFile( - path.join(distDir, 'index.css'), - 'utf8', - ); - assert(css.includes('.local')); - assert(css.includes('.index')); + 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]), + ), + ); + }); - assert.equal(css.split('\n').length, 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, + }, + }, + ); - it('should produce a sourcemap when sourceMaps are used', async function () { - await bundle(path.join(__dirname, '/integration/cssnano/index.js'), { + 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 handle quote in CSS URL correctly', async function () { + await bundle(path.join(__dirname, '/integration/css-url-quote/index.css')); + + let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8'); + + assert( + css.includes( + 'url("data:image/svg+xml;utf8,with quote \\" and escape \\\\");', + ), + ); + }); + + 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 throw a diagnostic for relative url() dependencies in custom properties', async function () { + let fixture = path.join( + __dirname, + 'integration/css-url-custom-property/index.css', + ); + let code = await inputFS.readFileSync(fixture, 'utf8'); + // $FlowFixMe + await assert.rejects( + () => + bundle(fixture, { 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, + }), + { + name: 'BuildError', + diagnostics: [ + { + message: + 'Ambiguous url() in custom property. Relative paths are resolved from the location the var() is used, not where the custom property is defined. Use an absolute URL instead.', + origin: '@parcel/transformer-css', + name: 'SyntaxError', + stack: undefined, + codeFrames: [ + { + filePath: fixture, + code, + codeHighlights: [ + { + start: { + line: 2, + column: 11, + }, + end: { + line: 2, + column: 11, + }, + }, + ], + }, + ], + hints: [ + 'Replace with: url(/integration/css-url-custom-property/foo.png)', + ], + documentationURL: 'https://parceljs.org/languages/css/#url()', }, - }); - let css = await outputFS.readFile( - path.join(distDir, 'text.css'), - 'utf8', - ); - assert.equal( - css.trim(), - `.svg-img { + ], + }, + ); + }); + + 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'), + ); - let res = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8'); - assert( - new RegExp(`@import "http://example.com/external.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"; .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/integration-tests/test/integration/css-url-custom-property/index.css b/packages/core/integration-tests/test/integration/css-url-custom-property/index.css new file mode 100644 index 00000000000..e64216d79ae --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-url-custom-property/index.css @@ -0,0 +1,3 @@ +.foo { + --test: url(foo.png); +} diff --git a/packages/core/integration-tests/test/integration/css-url-quote/index.css b/packages/core/integration-tests/test/integration/css-url-quote/index.css new file mode 100644 index 00000000000..0da4f256ed0 --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-url-quote/index.css @@ -0,0 +1,5 @@ +.quotes { + background-image: url('data:image/svg+xml;utf8,with quote " and escape \\'); + width: 100px; + height: 100px; +} diff --git a/packages/core/integration-tests/test/integration/css-url-quote/index.js b/packages/core/integration-tests/test/integration/css-url-quote/index.js new file mode 100644 index 00000000000..14400a424cd --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-url-quote/index.js @@ -0,0 +1,5 @@ +require('./index.css'); + +module.exports = function () { + return 2; +}; diff --git a/packages/core/integration-tests/test/integration/dynamic-imports-high-prio/async.js b/packages/core/integration-tests/test/integration/dynamic-imports-high-prio/async.js new file mode 100644 index 00000000000..7c645e42fb7 --- /dev/null +++ b/packages/core/integration-tests/test/integration/dynamic-imports-high-prio/async.js @@ -0,0 +1 @@ +export default {}; \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/dynamic-imports-high-prio/index.js b/packages/core/integration-tests/test/integration/dynamic-imports-high-prio/index.js new file mode 100644 index 00000000000..0a0f551e1ca --- /dev/null +++ b/packages/core/integration-tests/test/integration/dynamic-imports-high-prio/index.js @@ -0,0 +1 @@ +export default import('./async').then(() => document.head.children); diff --git a/packages/core/integration-tests/test/integration/jsx-automatic-16/index.js b/packages/core/integration-tests/test/integration/jsx-automatic-16/index.js new file mode 100644 index 00000000000..8d097d55d7f --- /dev/null +++ b/packages/core/integration-tests/test/integration/jsx-automatic-16/index.js @@ -0,0 +1 @@ +module.exports =
; diff --git a/packages/core/integration-tests/test/integration/jsx-automatic-16/node_modules/react/jsx-dev-runtime.js b/packages/core/integration-tests/test/integration/jsx-automatic-16/node_modules/react/jsx-dev-runtime.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/integration-tests/test/integration/jsx-automatic-16/node_modules/react/jsx-runtime.js b/packages/core/integration-tests/test/integration/jsx-automatic-16/node_modules/react/jsx-runtime.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/integration-tests/test/integration/jsx-automatic-16/node_modules/react/package.json b/packages/core/integration-tests/test/integration/jsx-automatic-16/node_modules/react/package.json new file mode 100644 index 00000000000..bcbea4166f7 --- /dev/null +++ b/packages/core/integration-tests/test/integration/jsx-automatic-16/node_modules/react/package.json @@ -0,0 +1,3 @@ +{ + "name": "react" +} diff --git a/packages/core/integration-tests/test/integration/jsx-automatic-16/package.json b/packages/core/integration-tests/test/integration/jsx-automatic-16/package.json new file mode 100644 index 00000000000..8716e63d8d1 --- /dev/null +++ b/packages/core/integration-tests/test/integration/jsx-automatic-16/package.json @@ -0,0 +1,6 @@ +{ + "private": true, + "dependencies": { + "react": "16.14.0" + } +} diff --git a/packages/core/integration-tests/test/integration/jsx-automatic-16/yarn.lock b/packages/core/integration-tests/test/integration/jsx-automatic-16/yarn.lock new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/integration-tests/test/integration/sourcemap-css-import/style.css b/packages/core/integration-tests/test/integration/sourcemap-css-import/style.css index 01ef4f07c71..5e2dc1491de 100644 --- a/packages/core/integration-tests/test/integration/sourcemap-css-import/style.css +++ b/packages/core/integration-tests/test/integration/sourcemap-css-import/style.css @@ -1,8 +1,7 @@ @import "./other-style.css"; +@import "./another-style.css"; body { background-color: red; -} - -@import "./another-style.css"; +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/javascript.js b/packages/core/integration-tests/test/javascript.js index f58347ca760..39867be8942 100644 --- a/packages/core/integration-tests/test/javascript.js +++ b/packages/core/integration-tests/test/javascript.js @@ -594,20 +594,20 @@ describe('javascript', function () { let output = await run(b); let headChildren = await output.default; - assert.equal(headChildren.length, 3); + assert.strictEqual(headChildren.length, 4); - assert(headChildren[0].tag === 'script'); - assert(headChildren[0].src.match(/async\..*\.js/)); + assert.strictEqual(headChildren[1].tag, 'script'); + assert(headChildren[1].src.match(/async\..*\.js/)); - assert(headChildren[1].tag === 'link'); - assert(headChildren[1].rel === 'prefetch'); - assert(headChildren[1].as === 'script'); - assert(headChildren[1].href.match(/prefetched\..*\.js/)); + assert.strictEqual(headChildren[2].tag, 'link'); + assert.strictEqual(headChildren[2].rel, 'prefetch'); + assert.strictEqual(headChildren[2].as, 'script'); + assert(headChildren[2].href.match(/prefetched\..*\.js/)); - assert(headChildren[2].tag === 'link'); - assert(headChildren[2].rel === 'prefetch'); - assert(headChildren[2].as === 'style'); - assert(headChildren[2].href.match(/prefetched\..*\.css/)); + assert.strictEqual(headChildren[3].tag, 'link'); + assert.strictEqual(headChildren[3].rel, 'prefetch'); + assert.strictEqual(headChildren[3].as, 'style'); + assert(headChildren[3].href.match(/prefetched\..*\.css/)); }); it('should load additional links that were prefetched', async function () { @@ -623,7 +623,7 @@ describe('javascript', function () { await outputReturn.loadDependency(); let headChildren = outputReturn.children; - assert.equal(headChildren.length, 5); + assert.equal(headChildren.length, 7); let cssBundles = headChildren.filter(child => child.href?.match(/prefetched-loaded\..*\.css/), ); @@ -647,20 +647,17 @@ describe('javascript', function () { let output = await run(b); let headChildren = await output.default; - assert(headChildren.length === 3); - - assert(headChildren[0].tag === 'script'); - assert(headChildren[0].src.match(/async\..*\.js/)); - - assert(headChildren[1].tag === 'link'); - assert(headChildren[1].rel === 'preload'); - assert(headChildren[1].as === 'script'); - assert(headChildren[1].href.match(/preloaded\..*\.js/)); + assert(headChildren.length === 4); assert(headChildren[2].tag === 'link'); assert(headChildren[2].rel === 'preload'); - assert(headChildren[2].as === 'style'); - assert(headChildren[2].href.match(/preloaded\..*\.css/)); + assert(headChildren[2].as === 'script'); + assert(headChildren[2].href.match(/preloaded\..*\.js/)); + + assert(headChildren[3].tag === 'link'); + assert(headChildren[3].rel === 'preload'); + assert(headChildren[3].as === 'style'); + assert(headChildren[3].href.match(/preloaded\..*\.css/)); }); // TODO: Implement when we can evaluate bundles against esmodule targets @@ -874,6 +871,31 @@ describe('javascript', function () { assert.deepEqual(res, {default: 42}); }); + it('dynamic imports loaded as high-priority scripts when not all engines support esmodules natively', async function () { + let b = await bundle( + path.join(__dirname, '/integration/dynamic-imports-high-prio/index.js'), + { + defaultTargetOptions: { + engines: { + browsers: 'IE 11', + }, + }, + }, + ); + + let output = await run(b); + let headChildren = await output.default; + + assert(headChildren[0].tag === 'link'); + assert(headChildren[0].rel === 'preload'); + assert(headChildren[0].as === 'script'); + + assert(headChildren[1].tag === 'script'); + assert(headChildren[1].src.match(/async\..*\.js/)); + + assert(headChildren[0].href === headChildren[1].src); + }); + it('should support bundling workers with dynamic import in both page and worker', async function () { let b = await bundle( path.join(__dirname, '/integration/worker-dynamic/index-async.js'), diff --git a/packages/core/integration-tests/test/transpilation.js b/packages/core/integration-tests/test/transpilation.js index c5e52a89bc7..a630267eee5 100644 --- a/packages/core/integration-tests/test/transpilation.js +++ b/packages/core/integration-tests/test/transpilation.js @@ -203,6 +203,16 @@ describe('transpilation', function () { assert(file.includes('_jsxDevRuntime.jsxDEV("div"')); }); + it('should support the automatic JSX runtime with React ^16.14.0', async function () { + let b = await bundle( + path.join(__dirname, '/integration/jsx-automatic-16/index.js'), + ); + + let file = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8'); + assert(file.includes('react/jsx-dev-runtime')); + assert(file.includes('_jsxDevRuntime.jsxDEV("div"')); + }); + it('should support the automatic JSX runtime with React 18 prereleases', async function () { let b = await bundle( path.join(__dirname, '/integration/jsx-automatic-18/index.js'), diff --git a/packages/core/is-v2-ready-yet/package.json b/packages/core/is-v2-ready-yet/package.json index e12bf0f3ceb..acbf8cf55ec 100644 --- a/packages/core/is-v2-ready-yet/package.json +++ b/packages/core/is-v2-ready-yet/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/is-v2-ready-yet", - "version": "2.3.2", + "version": "2.4.0", "private": true, "license": "MIT", "repository": { @@ -13,7 +13,7 @@ "build-app": "yarn parcel build index.html" }, "dependencies": { - "@parcel/integration-tests": "2.3.2", + "@parcel/integration-tests": "2.4.0", "react": "^17.0.2", "react-dom": "^17.0.2", "victory": "^31.0.1" diff --git a/packages/core/logger/package.json b/packages/core/logger/package.json index 7e5f96c9eb9..452227656e2 100644 --- a/packages/core/logger/package.json +++ b/packages/core/logger/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/logger", - "version": "2.3.2", + "version": "2.4.0", "description": "Blazing fast, zero configuration web application bundler", "license": "MIT", "publishConfig": { @@ -20,7 +20,7 @@ "node": ">= 12.0.0" }, "dependencies": { - "@parcel/diagnostic": "2.3.2", - "@parcel/events": "2.3.2" + "@parcel/diagnostic": "2.4.0", + "@parcel/events": "2.4.0" } } diff --git a/packages/core/markdown-ansi/package.json b/packages/core/markdown-ansi/package.json index 2c798ed939a..58ad0ac2fcb 100644 --- a/packages/core/markdown-ansi/package.json +++ b/packages/core/markdown-ansi/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/markdown-ansi", - "version": "2.3.2", + "version": "2.4.0", "description": "Blazing fast, zero configuration web application bundler", "publishConfig": { "access": "public" diff --git a/packages/core/package-manager/package.json b/packages/core/package-manager/package.json index 25fa20f83c0..f9fb0836879 100644 --- a/packages/core/package-manager/package.json +++ b/packages/core/package-manager/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/package-manager", - "version": "2.3.2", + "version": "2.4.0", "description": "Blazing fast, zero configuration web application bundler", "license": "MIT", "publishConfig": { @@ -40,12 +40,12 @@ } }, "dependencies": { - "@parcel/diagnostic": "2.3.2", - "@parcel/fs": "2.3.2", - "@parcel/logger": "2.3.2", - "@parcel/types": "2.3.2", - "@parcel/utils": "2.3.2", - "@parcel/workers": "2.3.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/fs": "2.4.0", + "@parcel/logger": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", + "@parcel/workers": "2.4.0", "semver": "^5.7.1" }, "devDependencies": { @@ -55,7 +55,7 @@ "split2": "^3.1.1" }, "peerDependencies": { - "@parcel/core": "^2.3.2" + "@parcel/core": "^2.4.0" }, "browser": { "./src/Npm.js": false, diff --git a/packages/core/parcel/package.json b/packages/core/parcel/package.json index c5a117863c9..9cc61b69c16 100644 --- a/packages/core/parcel/package.json +++ b/packages/core/parcel/package.json @@ -1,6 +1,6 @@ { "name": "parcel", - "version": "2.3.2", + "version": "2.4.0", "description": "Blazing fast, zero configuration web application bundler", "license": "MIT", "publishConfig": { @@ -21,22 +21,22 @@ "node": ">= 12.0.0" }, "dependencies": { - "@parcel/config-default": "2.3.2", - "@parcel/core": "2.3.2", - "@parcel/diagnostic": "2.3.2", - "@parcel/events": "2.3.2", - "@parcel/fs": "2.3.2", - "@parcel/logger": "2.3.2", - "@parcel/package-manager": "2.3.2", - "@parcel/reporter-cli": "2.3.2", - "@parcel/reporter-dev-server": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/config-default": "2.4.0", + "@parcel/core": "2.4.0", + "@parcel/diagnostic": "2.4.0", + "@parcel/events": "2.4.0", + "@parcel/fs": "2.4.0", + "@parcel/logger": "2.4.0", + "@parcel/package-manager": "2.4.0", + "@parcel/reporter-cli": "2.4.0", + "@parcel/reporter-dev-server": "2.4.0", + "@parcel/utils": "2.4.0", "chalk": "^4.1.0", "commander": "^7.0.0", "get-port": "^4.2.0", "v8-compile-cache": "^2.0.0" }, "devDependencies": { - "@parcel/babel-register": "2.3.2" + "@parcel/babel-register": "2.4.0" } } diff --git a/packages/core/plugin/package.json b/packages/core/plugin/package.json index e91362c3d1c..d92fc086d06 100644 --- a/packages/core/plugin/package.json +++ b/packages/core/plugin/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/plugin", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -23,6 +23,6 @@ "check-ts": "tsc --noEmit src/PluginAPI.d.ts" }, "dependencies": { - "@parcel/types": "2.3.2" + "@parcel/types": "2.4.0" } } diff --git a/packages/core/register/package.json b/packages/core/register/package.json index ab688d3c613..a78f96e374b 100644 --- a/packages/core/register/package.json +++ b/packages/core/register/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/register", - "version": "2.3.2", + "version": "2.4.0", "private": true, "license": "MIT", "publishConfig": { @@ -24,10 +24,10 @@ "clean": "rimraf .parcel-cache" }, "dependencies": { - "@parcel/config-default": "2.3.2", - "@parcel/core": "2.3.2", - "@parcel/fs": "2.3.2", - "@parcel/package-manager": "2.3.2", + "@parcel/config-default": "2.4.0", + "@parcel/core": "2.4.0", + "@parcel/fs": "2.4.0", + "@parcel/package-manager": "2.4.0", "pirates": "^4.0.0" } } diff --git a/packages/core/test-utils/package.json b/packages/core/test-utils/package.json index ad0555245f0..023ff5dc84e 100644 --- a/packages/core/test-utils/package.json +++ b/packages/core/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/test-utils", - "version": "2.3.2", + "version": "2.4.0", "description": "Blazing fast, zero configuration web application bundler", "license": "MIT", "private": true, @@ -13,11 +13,11 @@ "node": ">= 12.0.0" }, "dependencies": { - "@parcel/config-default": "2.3.2", - "@parcel/core": "2.3.2", - "@parcel/fs": "2.3.2", - "@parcel/package-manager": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/config-default": "2.4.0", + "@parcel/core": "2.4.0", + "@parcel/fs": "2.4.0", + "@parcel/package-manager": "2.4.0", + "@parcel/utils": "2.4.0", "chalk": "^4.1.0", "ncp": "^2.0.0", "nullthrows": "^1.1.1", 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/core/types/index.js b/packages/core/types/index.js index 3a6de594658..c79df875b66 100644 --- a/packages/core/types/index.js +++ b/packages/core/types/index.js @@ -744,9 +744,9 @@ export interface MutableAsset extends BaseAsset { setBuffer(Buffer): void; /** Sets the asset contents as a stream. */ setStream(Readable): void; - /** Returns whether the AST has been modified. */ - setAST(AST): void; /** Sets the asset's AST. */ + setAST(AST): void; + /** Returns whether the AST has been modified. */ isASTDirty(): boolean; /** Sets the asset's source map. */ setMap(?SourceMap): void; diff --git a/packages/core/types/package.json b/packages/core/types/package.json index 29c236b4ccd..461c9e81d05 100644 --- a/packages/core/types/package.json +++ b/packages/core/types/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/types", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "main": "src/index.js", "types": "lib/index.d.ts", @@ -16,12 +16,12 @@ "check-ts": "tsc --noEmit lib/index.d.ts" }, "dependencies": { - "@parcel/cache": "2.3.2", - "@parcel/diagnostic": "2.3.2", - "@parcel/fs": "2.3.2", - "@parcel/package-manager": "2.3.2", + "@parcel/cache": "2.4.0", + "@parcel/diagnostic": "2.4.0", + "@parcel/fs": "2.4.0", + "@parcel/package-manager": "2.4.0", "@parcel/source-map": "^2.0.0", - "@parcel/workers": "2.3.2", + "@parcel/workers": "2.4.0", "utility-types": "^3.10.0" } } diff --git a/packages/core/utils/package.json b/packages/core/utils/package.json index aa137445b7b..c1d457c412b 100644 --- a/packages/core/utils/package.json +++ b/packages/core/utils/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/utils", - "version": "2.3.2", + "version": "2.4.0", "description": "Blazing fast, zero configuration web application bundler", "license": "MIT", "publishConfig": { @@ -33,11 +33,11 @@ } }, "dependencies": { - "@parcel/codeframe": "2.3.2", - "@parcel/diagnostic": "2.3.2", - "@parcel/hash": "2.3.2", - "@parcel/logger": "2.3.2", - "@parcel/markdown-ansi": "2.3.2", + "@parcel/codeframe": "2.4.0", + "@parcel/diagnostic": "2.4.0", + "@parcel/hash": "2.4.0", + "@parcel/logger": "2.4.0", + "@parcel/markdown-ansi": "2.4.0", "@parcel/source-map": "^2.0.0", "chalk": "^4.1.0" }, diff --git a/packages/core/utils/src/replaceBundleReferences.js b/packages/core/utils/src/replaceBundleReferences.js index 8161ac299ad..25eaf2c996c 100644 --- a/packages/core/utils/src/replaceBundleReferences.js +++ b/packages/core/utils/src/replaceBundleReferences.js @@ -33,6 +33,7 @@ export function replaceURLReferences({ bundleGraph, contents, map, + getReplacement = s => s, relative = true, }: {| bundle: NamedBundle, @@ -40,6 +41,7 @@ export function replaceURLReferences({ contents: string, relative?: boolean, map?: ?SourceMap, + getReplacement?: string => string, |}): {|+contents: string, +map: ?SourceMap|} { let replacements = new Map(); let urlDependencies = []; @@ -61,7 +63,7 @@ export function replaceURLReferences({ if (resolved == null) { replacements.set(placeholder, { from: placeholder, - to: dependency.specifier, + to: getReplacement(dependency.specifier), }); continue; } @@ -79,6 +81,7 @@ export function replaceURLReferences({ fromBundle: bundle, toBundle: resolved, relative, + getReplacement, }), ); } @@ -156,11 +159,13 @@ export function getURLReplacement({ fromBundle, toBundle, relative, + getReplacement, }: {| dependency: Dependency, fromBundle: NamedBundle, toBundle: NamedBundle, relative: boolean, + getReplacement?: string => string, |}): {|from: string, to: string|} { let to; @@ -191,9 +196,10 @@ export function getURLReplacement({ let placeholder = dependency.meta?.placeholder ?? dependency.id; invariant(typeof placeholder === 'string'); + return { from: placeholder, - to, + to: getReplacement ? getReplacement(to) : to, }; } diff --git a/packages/core/workers/package.json b/packages/core/workers/package.json index eaa5e8e0e19..98221a9a66a 100644 --- a/packages/core/workers/package.json +++ b/packages/core/workers/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/workers", - "version": "2.3.2", + "version": "2.4.0", "description": "Blazing fast, zero configuration web application bundler", "license": "MIT", "publishConfig": { @@ -21,15 +21,15 @@ "node": ">= 12.0.0" }, "dependencies": { - "@parcel/diagnostic": "2.3.2", - "@parcel/logger": "2.3.2", - "@parcel/types": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/logger": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", "chrome-trace-event": "^1.0.2", "nullthrows": "^1.1.1" }, "peerDependencies": { - "@parcel/core": "^2.3.2" + "@parcel/core": "^2.4.0" }, "browser": { "./src/cpuCount.js": false, diff --git a/packages/dev/babel-preset/package.json b/packages/dev/babel-preset/package.json index 645c4d683d8..efade3e71f5 100644 --- a/packages/dev/babel-preset/package.json +++ b/packages/dev/babel-preset/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/babel-preset", - "version": "2.3.2", + "version": "2.4.0", "private": true, "license": "MIT", "repository": { diff --git a/packages/dev/babel-register/package.json b/packages/dev/babel-register/package.json index e5be41f25f2..309e2c6f62a 100644 --- a/packages/dev/babel-register/package.json +++ b/packages/dev/babel-register/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/babel-register", - "version": "2.3.2", + "version": "2.4.0", "description": "Blazing fast, zero configuration web application bundler", "license": "MIT", "private": true, @@ -10,7 +10,7 @@ }, "dependencies": { "@babel/register": "^7.4.4", - "@parcel/babel-preset": "2.3.2", + "@parcel/babel-preset": "2.4.0", "resolve": "^1.12.0" } } diff --git a/packages/dev/eslint-config-browser/package.json b/packages/dev/eslint-config-browser/package.json index d62c693be00..327b54962fe 100644 --- a/packages/dev/eslint-config-browser/package.json +++ b/packages/dev/eslint-config-browser/package.json @@ -1,8 +1,8 @@ { "name": "@parcel/eslint-config-browser", "private": true, - "version": "2.3.2", + "version": "2.4.0", "dependencies": { - "@parcel/eslint-config": "2.3.2" + "@parcel/eslint-config": "2.4.0" } } diff --git a/packages/dev/eslint-config/package.json b/packages/dev/eslint-config/package.json index 3a1d150268c..7f408934bde 100644 --- a/packages/dev/eslint-config/package.json +++ b/packages/dev/eslint-config/package.json @@ -1,10 +1,10 @@ { "name": "@parcel/eslint-config", "private": true, - "version": "2.3.2", + "version": "2.4.0", "dependencies": { "@babel/eslint-parser": "^7.12.1", - "@parcel/eslint-plugin": "2.3.2", + "@parcel/eslint-plugin": "2.4.0", "eslint-config-prettier": "^7.2.0", "eslint-plugin-flowtype": "^5.2.0", "eslint-plugin-import": "^2.22.1", diff --git a/packages/dev/eslint-plugin/package.json b/packages/dev/eslint-plugin/package.json index 69833d1119d..a9b9fa03f6a 100644 --- a/packages/dev/eslint-plugin/package.json +++ b/packages/dev/eslint-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@parcel/eslint-plugin", "private": true, - "version": "2.3.2", + "version": "2.4.0", "main": "index.js", "scripts": {}, "dependencies": { diff --git a/packages/dev/esm-fuzzer/package.json b/packages/dev/esm-fuzzer/package.json index b05f281e7a4..3948169edaa 100644 --- a/packages/dev/esm-fuzzer/package.json +++ b/packages/dev/esm-fuzzer/package.json @@ -1,6 +1,6 @@ { "name": "fuzzer", - "version": "2.3.2", + "version": "2.4.0", "private": true, "scripts": { "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules -r @parcel/babel-register index.js" diff --git a/packages/examples/eslint-example/package.json b/packages/examples/eslint-example/package.json index 5cf1f1ee1f1..ba1a8902fad 100644 --- a/packages/examples/eslint-example/package.json +++ b/packages/examples/eslint-example/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/eslint-example", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "private": true, "scripts": { @@ -17,8 +17,8 @@ } }, "devDependencies": { - "@parcel/babel-register": "2.3.2", - "@parcel/core": "2.3.2", - "@parcel/validator-eslint": "2.3.2" + "@parcel/babel-register": "2.4.0", + "@parcel/core": "2.4.0", + "@parcel/validator-eslint": "2.4.0" } } diff --git a/packages/examples/html/package.json b/packages/examples/html/package.json index 9c36d7767b3..dbc75acbf44 100644 --- a/packages/examples/html/package.json +++ b/packages/examples/html/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/html-example", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "private": true, "scripts": { @@ -12,8 +12,8 @@ "not firefox < 67" ], "devDependencies": { - "@parcel/babel-register": "2.3.2", - "parcel": "2.3.2" + "@parcel/babel-register": "2.4.0", + "parcel": "2.4.0" }, "dependencies": { "lodash": "^4.17.11", diff --git a/packages/examples/internalize-example/package.json b/packages/examples/internalize-example/package.json index 80bb3e53e94..91805aac78d 100644 --- a/packages/examples/internalize-example/package.json +++ b/packages/examples/internalize-example/package.json @@ -1,6 +1,6 @@ { "name": "internalize-example", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "private": true } diff --git a/packages/examples/kitchen-sink/package.json b/packages/examples/kitchen-sink/package.json index b4a1c31528c..48969d1d32e 100644 --- a/packages/examples/kitchen-sink/package.json +++ b/packages/examples/kitchen-sink/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/kitchen-sink-example", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "private": true, "scripts": { @@ -8,11 +8,11 @@ "build": "rm -rf dist && parcel build src/index.html --no-cache" }, "devDependencies": { - "@parcel/babel-register": "2.3.2", - "@parcel/config-default": "2.3.2", - "@parcel/optimizer-esbuild": "2.3.2", - "@parcel/reporter-sourcemap-visualiser": "2.3.2", - "parcel": "2.3.2" + "@parcel/babel-register": "2.4.0", + "@parcel/config-default": "2.4.0", + "@parcel/optimizer-esbuild": "2.4.0", + "@parcel/reporter-sourcemap-visualiser": "2.4.0", + "parcel": "2.4.0" }, "browser": "dist/legacy/index.html", "browserModern": "dist/modern/index.html", diff --git a/packages/examples/react-hmr/package.json b/packages/examples/react-hmr/package.json index 733e8ba84e2..d3e4774afed 100644 --- a/packages/examples/react-hmr/package.json +++ b/packages/examples/react-hmr/package.json @@ -1,13 +1,13 @@ { "name": "@parcel/react-hmr-example", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "private": true, "scripts": { "demo": "parcel serve src/index.html --no-cache --https" }, "devDependencies": { - "parcel": "2.3.2" + "parcel": "2.4.0" }, "browser": "dist/legacy/index.html", "browserModern": "dist/modern/index.html", diff --git a/packages/examples/react-refresh/package.json b/packages/examples/react-refresh/package.json index 0924d7490c8..1a4f12124fa 100644 --- a/packages/examples/react-refresh/package.json +++ b/packages/examples/react-refresh/package.json @@ -1,14 +1,14 @@ { "name": "@parcel/react-refresh-example", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "private": true, "scripts": { "start": "parcel src/index.html" }, "devDependencies": { - "@parcel/babel-register": "2.3.2", - "@parcel/core": "2.3.2" + "@parcel/babel-register": "2.4.0", + "@parcel/core": "2.4.0" }, "dependencies": { "react": "^17.0.2", diff --git a/packages/examples/simple/package.json b/packages/examples/simple/package.json index bb95f475f2b..d596993fc26 100644 --- a/packages/examples/simple/package.json +++ b/packages/examples/simple/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/simple-example", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "private": true, "scripts": { @@ -8,8 +8,8 @@ "clean-demo": "rm -rf .parcel-cache dist && yarn demo" }, "devDependencies": { - "@parcel/babel-register": "2.3.2", - "@parcel/core": "2.3.2" + "@parcel/babel-register": "2.4.0", + "@parcel/core": "2.4.0" }, "browser": "dist/legacy/index.js", "browserModern": "dist/modern/index.js", diff --git a/packages/examples/three/package.json b/packages/examples/three/package.json index 93a4605376a..6753c56c43c 100644 --- a/packages/examples/three/package.json +++ b/packages/examples/three/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/three-js-stresstest", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "private": true, "scripts": { @@ -27,7 +27,7 @@ } }, "devDependencies": { - "@parcel/config-default": "2.3.2", - "parcel": "2.3.2" + "@parcel/config-default": "2.4.0", + "parcel": "2.4.0" } } diff --git a/packages/examples/ts-example/package.json b/packages/examples/ts-example/package.json index 0f6c88af664..b0a94a1ffb0 100644 --- a/packages/examples/ts-example/package.json +++ b/packages/examples/ts-example/package.json @@ -1,14 +1,14 @@ { "name": "@parcel/ts-example", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "private": true, "scripts": { "demo": "parcel build src/index.ts" }, "devDependencies": { - "@parcel/babel-register": "2.3.2", - "@parcel/core": "2.3.2" + "@parcel/babel-register": "2.4.0", + "@parcel/core": "2.4.0" }, "main": "dist/main.js", "module": "dist/module.js", diff --git a/packages/examples/ts-typecheck-example/package.json b/packages/examples/ts-typecheck-example/package.json index 3f80c973eee..36abb908ce5 100644 --- a/packages/examples/ts-typecheck-example/package.json +++ b/packages/examples/ts-typecheck-example/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/ts-typecheck-example", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "private": true, "scripts": { @@ -17,8 +17,8 @@ } }, "devDependencies": { - "@parcel/babel-register": "2.3.2", - "@parcel/core": "2.3.2", - "@parcel/validator-typescript": "2.3.2" + "@parcel/babel-register": "2.4.0", + "@parcel/core": "2.4.0", + "@parcel/validator-typescript": "2.4.0" } } diff --git a/packages/namers/default/package.json b/packages/namers/default/package.json index 7d57d67c057..9210f19e053 100644 --- a/packages/namers/default/package.json +++ b/packages/namers/default/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/namer-default", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,11 +17,11 @@ "source": "src/DefaultNamer.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/diagnostic": "2.3.2", - "@parcel/plugin": "2.3.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", "nullthrows": "^1.1.1" } } diff --git a/packages/optimizers/blob-url/package.json b/packages/optimizers/blob-url/package.json index 7314e26df23..6f2af11a8dc 100644 --- a/packages/optimizers/blob-url/package.json +++ b/packages/optimizers/blob-url/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/optimizer-blob-url", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,10 +17,10 @@ "source": "src/BlobURLOptimizer.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2" + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0" } } diff --git a/packages/optimizers/css/package.json b/packages/optimizers/css/package.json index 183963682a3..f218af735a4 100644 --- a/packages/optimizers/css/package.json +++ b/packages/optimizers/css/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/optimizer-css", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,13 +17,14 @@ "source": "src/CSSOptimizer.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/css": "^1.0.3", - "@parcel/plugin": "2.3.2", + "@parcel/css": "^1.7.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", "@parcel/source-map": "^2.0.0", - "@parcel/utils": "2.3.2", + "@parcel/utils": "2.4.0", "browserslist": "^4.6.6", "nullthrows": "^1.1.1" } 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/optimizers/cssnano/package.json b/packages/optimizers/cssnano/package.json index 87c8c5a7228..e7ae02511ea 100644 --- a/packages/optimizers/cssnano/package.json +++ b/packages/optimizers/cssnano/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/optimizer-cssnano", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,10 +17,10 @@ "source": "src/CSSNanoOptimizer.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", + "@parcel/plugin": "2.4.0", "@parcel/source-map": "^2.0.0", "cssnano": "^5.0.15", "postcss": "^8.4.5" diff --git a/packages/optimizers/data-url/package.json b/packages/optimizers/data-url/package.json index 22a1f910a5b..139a8011993 100644 --- a/packages/optimizers/data-url/package.json +++ b/packages/optimizers/data-url/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/optimizer-data-url", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,11 +17,11 @@ "source": "src/DataURLOptimizer.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", "isbinaryfile": "^4.0.2", "mime": "^2.4.4" } diff --git a/packages/optimizers/esbuild/package.json b/packages/optimizers/esbuild/package.json index 4466e405426..b3829ff3110 100644 --- a/packages/optimizers/esbuild/package.json +++ b/packages/optimizers/esbuild/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/optimizer-esbuild", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,13 +17,13 @@ "source": "src/ESBuildOptimizer.js", "engines": { "node": ">= 10.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/diagnostic": "2.3.2", - "@parcel/plugin": "2.3.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", "@parcel/source-map": "^2.0.0", - "@parcel/utils": "2.3.2", + "@parcel/utils": "2.4.0", "esbuild": "^0.13.0", "nullthrows": "^1.1.1" } diff --git a/packages/optimizers/htmlnano/package.json b/packages/optimizers/htmlnano/package.json index 4c129a256db..bb558d44bac 100644 --- a/packages/optimizers/htmlnano/package.json +++ b/packages/optimizers/htmlnano/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/optimizer-htmlnano", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,10 +17,10 @@ "source": "src/HTMLNanoOptimizer.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", + "@parcel/plugin": "2.4.0", "htmlnano": "^2.0.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", diff --git a/packages/optimizers/image/package.json b/packages/optimizers/image/package.json index f6db4fcef57..841a01fa19e 100644 --- a/packages/optimizers/image/package.json +++ b/packages/optimizers/image/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/optimizer-image", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "main": "lib/ImageOptimizer.js", "source": "src/ImageOptimizer.js", @@ -17,7 +17,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "files": [ "lib", @@ -32,10 +32,10 @@ "build-release": "napi build --platform --release" }, "dependencies": { - "@parcel/diagnostic": "2.3.2", - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2", - "@parcel/workers": "2.3.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", + "@parcel/workers": "2.4.0", "detect-libc": "^1.0.3" }, "devDependencies": { diff --git a/packages/optimizers/svgo/package.json b/packages/optimizers/svgo/package.json index 22fbce56530..f982adfe9ba 100644 --- a/packages/optimizers/svgo/package.json +++ b/packages/optimizers/svgo/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/optimizer-svgo", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,12 +17,12 @@ "source": "src/SVGOOptimizer.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/diagnostic": "2.3.2", - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", "svgo": "^2.4.0" } } diff --git a/packages/optimizers/swc/package.json b/packages/optimizers/swc/package.json index 7789125524b..653a6bb5f68 100644 --- a/packages/optimizers/swc/package.json +++ b/packages/optimizers/swc/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/optimizer-swc", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,12 +17,12 @@ "source": "src/SwcOptimizer.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", + "@parcel/plugin": "2.4.0", "@parcel/source-map": "^2.0.0", - "@parcel/utils": "2.3.2", + "@parcel/utils": "2.4.0", "@swc/core": "^1.2.106", "nullthrows": "^1.1.1" } diff --git a/packages/optimizers/terser/package.json b/packages/optimizers/terser/package.json index 6c931145b67..6218739c499 100644 --- a/packages/optimizers/terser/package.json +++ b/packages/optimizers/terser/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/optimizer-terser", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,13 +17,13 @@ "source": "src/TerserOptimizer.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/diagnostic": "2.3.2", - "@parcel/plugin": "2.3.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", "@parcel/source-map": "^2.0.0", - "@parcel/utils": "2.3.2", + "@parcel/utils": "2.4.0", "nullthrows": "^1.1.1", "terser": "^5.2.0" } diff --git a/packages/packagers/css/package.json b/packages/packagers/css/package.json index cfdfdb9606c..dbf8d1ae90b 100644 --- a/packages/packagers/css/package.json +++ b/packages/packagers/css/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/packager-css", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,12 +17,12 @@ "source": "src/CSSPackager.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", + "@parcel/plugin": "2.4.0", "@parcel/source-map": "^2.0.0", - "@parcel/utils": "2.3.2", + "@parcel/utils": "2.4.0", "nullthrows": "^1.1.1" }, "devDependencies": { diff --git a/packages/packagers/css/src/CSSPackager.js b/packages/packagers/css/src/CSSPackager.js index 23be7bae163..ae2fbbef49b 100644 --- a/packages/packagers/css/src/CSSPackager.js +++ b/packages/packagers/css/src/CSSPackager.js @@ -129,6 +129,7 @@ export default (new Packager({ bundleGraph, contents, map, + getReplacement: escapeString, })); return replaceInlineReferences({ @@ -138,7 +139,7 @@ export default (new Packager({ getInlineBundleContents, getInlineReplacement: (dep, inlineType, contents) => ({ from: getSpecifier(dep), - to: contents, + to: escapeString(contents), }), map, }); @@ -153,6 +154,10 @@ export function getSpecifier(dep: Dependency): string { return dep.id; } +function escapeString(contents: string): string { + return contents.replace(/(["\\])/g, '\\$1'); +} + async function processCSSModule( options, logger, diff --git a/packages/packagers/html/package.json b/packages/packagers/html/package.json index bfebdfcc1a2..b6ae2fe08fd 100644 --- a/packages/packagers/html/package.json +++ b/packages/packagers/html/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/packager-html", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,12 +17,12 @@ "source": "src/HTMLPackager.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/types": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/plugin": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5" } diff --git a/packages/packagers/html/src/HTMLPackager.js b/packages/packagers/html/src/HTMLPackager.js index b30faf3a110..f92089f5f12 100644 --- a/packages/packagers/html/src/HTMLPackager.js +++ b/packages/packagers/html/src/HTMLPackager.js @@ -74,6 +74,7 @@ export default (new Packager({ bundleGraph, contents: html, relative: false, + getReplacement: contents => contents.replace(/"/g, '"'), }); return replaceInlineReferences({ diff --git a/packages/packagers/js/package.json b/packages/packagers/js/package.json index f2a55543626..b8f1b16992b 100644 --- a/packages/packagers/js/package.json +++ b/packages/packagers/js/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/packager-js", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,14 +17,14 @@ "source": "src/index.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/diagnostic": "2.3.2", - "@parcel/hash": "2.3.2", - "@parcel/plugin": "2.3.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/hash": "2.4.0", + "@parcel/plugin": "2.4.0", "@parcel/source-map": "^2.0.0", - "@parcel/utils": "2.3.2", + "@parcel/utils": "2.4.0", "globals": "^13.2.0", "nullthrows": "^1.1.1" } diff --git a/packages/packagers/js/src/index.js b/packages/packagers/js/src/index.js index 58c96fa4fb8..73f1ebc0aa6 100644 --- a/packages/packagers/js/src/index.js +++ b/packages/packagers/js/src/index.js @@ -72,6 +72,7 @@ export default (new Packager({ bundleGraph, contents, map, + getReplacement: s => JSON.stringify(s).slice(1, -1), })); } diff --git a/packages/packagers/raw-url/package.json b/packages/packagers/raw-url/package.json index 8b428f5b7f7..ef8768d2da5 100644 --- a/packages/packagers/raw-url/package.json +++ b/packages/packagers/raw-url/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/packager-raw-url", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,10 +17,10 @@ "source": "src/RawUrlPackager.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2" + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0" } } diff --git a/packages/packagers/raw-url/src/RawUrlPackager.js b/packages/packagers/raw-url/src/RawUrlPackager.js index cd73ce2bac2..e6641bf415b 100644 --- a/packages/packagers/raw-url/src/RawUrlPackager.js +++ b/packages/packagers/raw-url/src/RawUrlPackager.js @@ -17,6 +17,7 @@ export default (new Packager({ bundleGraph, contents: await assets[0].getCode(), relative: false, + getReplacement: s => s, }); return {contents}; }, diff --git a/packages/packagers/raw/package.json b/packages/packagers/raw/package.json index f5b7d2d1ec5..81b10a29d7b 100644 --- a/packages/packagers/raw/package.json +++ b/packages/packagers/raw/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/packager-raw", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,9 +17,9 @@ "source": "src/RawPackager.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2" + "@parcel/plugin": "2.4.0" } } diff --git a/packages/packagers/svg/package.json b/packages/packagers/svg/package.json index 7103ade1e58..fd49abbc1c5 100644 --- a/packages/packagers/svg/package.json +++ b/packages/packagers/svg/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/packager-svg", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,12 +17,12 @@ "source": "src/SVGPackager.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/types": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/plugin": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", "posthtml": "^0.16.4" } } diff --git a/packages/packagers/svg/src/SVGPackager.js b/packages/packagers/svg/src/SVGPackager.js index a2dd81e9004..3ee06bd7d20 100644 --- a/packages/packagers/svg/src/SVGPackager.js +++ b/packages/packagers/svg/src/SVGPackager.js @@ -58,6 +58,7 @@ export default (new Packager({ bundleGraph, contents: svg, relative: false, + getReplacement: contents => contents.replace(/"/g, '"'), }); return replaceInlineReferences({ diff --git a/packages/packagers/ts/package.json b/packages/packagers/ts/package.json index 3c8870c6e4e..5d32d236251 100644 --- a/packages/packagers/ts/package.json +++ b/packages/packagers/ts/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/packager-ts", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,9 +17,9 @@ "source": "src/TSPackager.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2" + "@parcel/plugin": "2.4.0" } } diff --git a/packages/packagers/xml/package.json b/packages/packagers/xml/package.json index 42325aef2af..4cb12d73646 100644 --- a/packages/packagers/xml/package.json +++ b/packages/packagers/xml/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/packager-xml", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,12 +17,12 @@ "source": "src/XMLPackager.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/types": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/plugin": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", "@xmldom/xmldom": "^0.7.5" } } diff --git a/packages/packagers/xml/src/XMLPackager.js b/packages/packagers/xml/src/XMLPackager.js index 7e267a2fb41..290c0c73ad9 100644 --- a/packages/packagers/xml/src/XMLPackager.js +++ b/packages/packagers/xml/src/XMLPackager.js @@ -68,6 +68,7 @@ export default (new Packager({ bundleGraph, contents: code, relative: false, + getReplacement: contents => contents.replace(/"/g, '"'), }); return replaceInlineReferences({ diff --git a/packages/reporters/build-metrics/package.json b/packages/reporters/build-metrics/package.json index 10352ff2c1e..cd11b7cbbbf 100644 --- a/packages/reporters/build-metrics/package.json +++ b/packages/reporters/build-metrics/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/reporter-build-metrics", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,10 +17,10 @@ "source": "src/BuildMetricsReporter.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2" + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0" } } diff --git a/packages/reporters/bundle-analyzer/package.json b/packages/reporters/bundle-analyzer/package.json index db0da1f365a..2dd510c229c 100644 --- a/packages/reporters/bundle-analyzer/package.json +++ b/packages/reporters/bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/reporter-bundle-analyzer", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,14 +17,14 @@ "source": "src/BundleAnalyzerReporter.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", "nullthrows": "^1.1.1" }, "devDependencies": { - "@parcel/types": "2.3.2" + "@parcel/types": "2.4.0" } } diff --git a/packages/reporters/bundle-analyzer/src/BundleAnalyzerReporter.js b/packages/reporters/bundle-analyzer/src/BundleAnalyzerReporter.js index 746f51c14fb..4cc515293ef 100644 --- a/packages/reporters/bundle-analyzer/src/BundleAnalyzerReporter.js +++ b/packages/reporters/bundle-analyzer/src/BundleAnalyzerReporter.js @@ -142,7 +142,7 @@ async function getBundleNode(bundle: PackagedBundle, options: PluginOptions) { } return { - label: bundle.filePath, + label: path.relative(options.projectRoot, bundle.filePath), weight: bundle.stats.size, groups: generateGroups(dirMap), }; diff --git a/packages/reporters/bundle-buddy/package.json b/packages/reporters/bundle-buddy/package.json index 1a7eaaf33d7..cf3c3606459 100644 --- a/packages/reporters/bundle-buddy/package.json +++ b/packages/reporters/bundle-buddy/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/reporter-bundle-buddy", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,9 +17,9 @@ "source": "src/BundleBuddyReporter.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2" + "@parcel/plugin": "2.4.0" } } diff --git a/packages/reporters/cli/package.json b/packages/reporters/cli/package.json index 0b08d993e6f..22cb75f7601 100644 --- a/packages/reporters/cli/package.json +++ b/packages/reporters/cli/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/reporter-cli", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,7 +17,7 @@ "source": "src/CLIReporter.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "targets": { "main": { @@ -31,9 +31,9 @@ } }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/types": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/plugin": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", "chalk": "^4.1.0", "term-size": "^2.2.1" }, diff --git a/packages/reporters/dev-server/package.json b/packages/reporters/dev-server/package.json index f99fce86af9..d1ae24e1572 100644 --- a/packages/reporters/dev-server/package.json +++ b/packages/reporters/dev-server/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/reporter-dev-server", - "version": "2.3.2", + "version": "2.4.0", "description": "Blazing fast, zero configuration web application bundler", "license": "MIT", "publishConfig": { @@ -18,7 +18,7 @@ "source": "src/ServerReporter.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "targets": { "main": { @@ -29,12 +29,12 @@ } }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2" + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0" }, "devDependencies": { - "@parcel/babel-preset": "2.3.2", - "@parcel/types": "2.3.2", + "@parcel/babel-preset": "2.4.0", + "@parcel/types": "2.4.0", "connect": "^3.7.0", "ejs": "^3.1.6", "http-proxy-middleware": "^2.0.1", diff --git a/packages/reporters/json/package.json b/packages/reporters/json/package.json index 6f845a943bf..02af6b3aa4b 100644 --- a/packages/reporters/json/package.json +++ b/packages/reporters/json/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/reporter-json", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,12 +17,12 @@ "source": "src/JSONReporter.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/types": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/plugin": "2.4.0", + "@parcel/types": "2.4.0", + "@parcel/utils": "2.4.0", "nullthrows": "^1.1.1" } } diff --git a/packages/reporters/sourcemap-visualiser/package.json b/packages/reporters/sourcemap-visualiser/package.json index 3421878c90a..17e11d749b9 100644 --- a/packages/reporters/sourcemap-visualiser/package.json +++ b/packages/reporters/sourcemap-visualiser/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/reporter-sourcemap-visualiser", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,14 +17,14 @@ "source": "src/SourceMapVisualiser.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", "nullthrows": "^1.1.1" }, "devDependencies": { - "@parcel/types": "2.3.2" + "@parcel/types": "2.4.0" } } diff --git a/packages/resolvers/default/package.json b/packages/resolvers/default/package.json index e69cba6dda1..7eea093f098 100644 --- a/packages/resolvers/default/package.json +++ b/packages/resolvers/default/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/resolver-default", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,11 +17,11 @@ "source": "src/DefaultResolver.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/node-resolver-core": "2.3.2", - "@parcel/plugin": "2.3.2" + "@parcel/node-resolver-core": "2.4.0", + "@parcel/plugin": "2.4.0" }, "devDependencies": { "@babel/core": "^7.12.2" diff --git a/packages/resolvers/glob/package.json b/packages/resolvers/glob/package.json index ae5cf930db1..fcf16352d37 100644 --- a/packages/resolvers/glob/package.json +++ b/packages/resolvers/glob/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/resolver-glob", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,12 +17,12 @@ "source": "src/GlobResolver.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/diagnostic": "2.3.2", - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", "nullthrows": "^1.1.1" } } diff --git a/packages/runtimes/hmr/package.json b/packages/runtimes/hmr/package.json index 282d597225f..6a101d7d7fd 100644 --- a/packages/runtimes/hmr/package.json +++ b/packages/runtimes/hmr/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/runtime-browser-hmr", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,10 +17,10 @@ "source": "src/HMRRuntime.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2" + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0" } } diff --git a/packages/runtimes/js/package.json b/packages/runtimes/js/package.json index 32fca252086..ebf4b364779 100644 --- a/packages/runtimes/js/package.json +++ b/packages/runtimes/js/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/runtime-js", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,11 +17,11 @@ "source": "src/JSRuntime.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", "nullthrows": "^1.1.1" } } diff --git a/packages/runtimes/js/src/helpers/browser/js-loader.js b/packages/runtimes/js/src/helpers/browser/js-loader.js index 867fa4f4d2b..0ab0f33f63e 100644 --- a/packages/runtimes/js/src/helpers/browser/js-loader.js +++ b/packages/runtimes/js/src/helpers/browser/js-loader.js @@ -13,6 +13,12 @@ module.exports = cacheLoader(function loadJSBundle(bundle) { return; } + var preloadLink = document.createElement('link'); + preloadLink.href = bundle; + preloadLink.rel = 'preload'; + preloadLink.as = 'script'; + document.head.appendChild(preloadLink); + var script = document.createElement('script'); script.async = true; script.type = 'text/javascript'; diff --git a/packages/runtimes/react-refresh/package.json b/packages/runtimes/react-refresh/package.json index adb331118c5..0aa66674d61 100644 --- a/packages/runtimes/react-refresh/package.json +++ b/packages/runtimes/react-refresh/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/runtime-react-refresh", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,11 +17,11 @@ "source": "src/ReactRefreshRuntime.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", "react-refresh": "^0.9.0" } } diff --git a/packages/runtimes/service-worker/package.json b/packages/runtimes/service-worker/package.json index bfb5fb895b8..a27da7b5c0f 100644 --- a/packages/runtimes/service-worker/package.json +++ b/packages/runtimes/service-worker/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/runtime-service-worker", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,11 +17,11 @@ "source": "./src/ServiceWorkerRuntime.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", - "@parcel/utils": "2.3.2", + "@parcel/plugin": "2.4.0", + "@parcel/utils": "2.4.0", "nullthrows": "^1.1.1" } } diff --git a/packages/transformers/babel/package.json b/packages/transformers/babel/package.json index 3effdf38a58..d2da8297388 100644 --- a/packages/transformers/babel/package.json +++ b/packages/transformers/babel/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/transformer-babel", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,13 +17,13 @@ "source": "src/BabelTransformer.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/diagnostic": "2.3.2", - "@parcel/plugin": "2.3.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", "@parcel/source-map": "^2.0.0", - "@parcel/utils": "2.3.2", + "@parcel/utils": "2.4.0", "browserslist": "^4.6.6", "json5": "^2.2.0", "nullthrows": "^1.1.1", @@ -33,6 +33,6 @@ "@babel/core": "^7.12.0", "@babel/preset-env": "^7.0.0", "@babel/types": "^7.12.0", - "@parcel/types": "2.3.2" + "@parcel/types": "2.4.0" } } diff --git a/packages/transformers/coffeescript/package.json b/packages/transformers/coffeescript/package.json index 6f62f42899b..be1942ff5d8 100644 --- a/packages/transformers/coffeescript/package.json +++ b/packages/transformers/coffeescript/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/transformer-coffeescript", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,12 +17,12 @@ "source": "src/CoffeeScriptTransformer.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/plugin": "2.3.2", + "@parcel/plugin": "2.4.0", "@parcel/source-map": "^2.0.0", - "@parcel/utils": "2.3.2", + "@parcel/utils": "2.4.0", "coffeescript": "^2.0.3", "nullthrows": "^1.1.1", "semver": "^5.7.1" 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..a7e43467062 100644 --- a/packages/transformers/css/package.json +++ b/packages/transformers/css/package.json @@ -1,6 +1,6 @@ { "name": "@parcel/transformer-css", - "version": "2.3.2", + "version": "2.4.0", "license": "MIT", "publishConfig": { "access": "public" @@ -17,19 +17,15 @@ "source": "src/CSSTransformer.js", "engines": { "node": ">= 12.0.0", - "parcel": "^2.3.2" + "parcel": "^2.4.0" }, "dependencies": { - "@parcel/hash": "2.3.2", - "@parcel/plugin": "2.3.2", + "@parcel/css": "^1.7.2", + "@parcel/diagnostic": "2.4.0", + "@parcel/plugin": "2.4.0", "@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" + "@parcel/utils": "2.4.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..0cf252b731b 100644 --- a/packages/transformers/css/src/CSSTransformer.js +++ b/packages/transformers/css/src/CSSTransformer.js @@ -1,376 +1,257 @@ -// @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, relativePath} 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); -} +import ThrowableDiagnostic, {errorToDiagnostic} from '@parcel/diagnostic'; 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 transform({asset, config, options}) { + let [code, originalMap] = await Promise.all([ + asset.getBuffer(), + asset.getMap(), + ]); + + let targets = getTargets(asset.env.engines.browsers); + let res; + try { + 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, + }); + } + } catch (err) { + err.filePath = asset.filePath; + let diagnostic = errorToDiagnostic(err, { + origin: '@parcel/transformer-css', + }); + if (err.data?.type === 'AmbiguousUrlInCustomProperty' && err.data.url) { + let p = + '/' + + relativePath( + options.projectRoot, + path.resolve(path.dirname(asset.filePath), err.data.url), + false, + ); + diagnostic[0].hints = [`Replace with: url(${p})`]; + diagnostic[0].documentationURL = + 'https://parceljs.org/languages/css/#url()'; + } - 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; + throw new ThrowableDiagnostic({ + diagnostic, + }); } - 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, - }); + if (originalMap) { + map.extends(originalMap); + } - let isCSSModule = - asset.meta.cssModulesCompiled !== true && - MODULE_BY_NAME_RE.test(asset.filePath); + asset.setMap(map); + } + + if (res.dependencies) { + for (let dep of res.dependencies) { + let loc = dep.loc; + if (originalMap) { + loc = remapSourceLocation(loc, 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]; + 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 program: Root = postcss.fromJSON(ast.program); let assets = [asset]; - if (isCSSModule) { - assets = await compileCSSModules(asset, env, program, resolve, options); - } - if (asset.meta.hasDependencies === false) { - return assets; - } + if (res.exports != null) { + let exports = res.exports; + asset.symbols.ensure(); + asset.symbols.set('default', 'default'); - 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 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]; - } + let dependencies = new Map(); + let selfReferences = new Set(); + let locals = new Map(); + let c = 0; + let depjs = ''; + let js = ''; - specifier = name.value; + let jsDeps = []; - 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