diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yml b/.github/ISSUE_TEMPLATE/1.bug_report.yml index 623e939c481ff86..dbce6318ee4afa2 100644 --- a/.github/ISSUE_TEMPLATE/1.bug_report.yml +++ b/.github/ISSUE_TEMPLATE/1.bug_report.yml @@ -20,7 +20,7 @@ body: label: Provide environment information description: Please run `next info` in the root directory of your project and paste the results. You might need to use `npx --no-install next info` if next is not in the current PATH. validations: - required: false + required: true - type: input attributes: label: What browser are you using? (if relevant) diff --git a/.github/ISSUE_TEMPLATE/2.example_bug_report.yml b/.github/ISSUE_TEMPLATE/2.example_bug_report.yml index 361d686362147ae..04483f5a4518cf4 100644 --- a/.github/ISSUE_TEMPLATE/2.example_bug_report.yml +++ b/.github/ISSUE_TEMPLATE/2.example_bug_report.yml @@ -20,7 +20,7 @@ body: label: Provide environment information description: Please run `next info` in the root directory of your project and paste the results. You might need to use `npx --no-install next info` if next is not in the current PATH. validations: - required: false + required: true - type: input attributes: label: Which example does this report relate to? diff --git a/docs/api-reference/next/image.md b/docs/api-reference/next/image.md index 0e3d2cb1617aa7f..f278c193a3481b6 100644 --- a/docs/api-reference/next/image.md +++ b/docs/api-reference/next/image.md @@ -16,7 +16,8 @@ description: Enable Image Optimization with the built-in Image component. | Version | Changes | | --------- | ------------------------------------------------------------------------------------------------- | -| `v12.0.9` | `lazyRoot` prop added | +| `v12.1.0` | `dangerouslyAllowSVG` and `contentSecurityPolicy` configuration added. | +| `v12.0.9` | `lazyRoot` prop added. | | `v12.0.0` | `formats` configuration added.
AVIF support added.
Wrapper `
` changed to ``. | | `v11.1.0` | `onLoadingComplete` and `lazyBoundary` props added. | | `v11.0.0` | `src` prop support for static import.
`placeholder` prop added.
`blurDataURL` prop added. | @@ -439,6 +440,21 @@ module.exports = { } ``` +### Dangerously Allow SVG + +The default [loader](#loader) does not optimize SVG images for a few reasons. First, SVG is a vector format meaning it can be resized losslessly. Second, SVG has many of the same features as HTML/CSS, which can lead to vulnerabilities without proper [Content Security Policy (CSP) headers](/docs/advanced-features/security-headers.md). + +If you need to serve SVG images with the default Image Optimization API, you can set `dangerouslyAllowSVG` and `contentSecurityPolicy` inside your `next.config.js`: + +```js +module.exports = { + images: { + dangerouslyAllowSVG: true, + contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;", + }, +} +``` + ## Related For an overview of the Image component features and usage guidelines, see: diff --git a/errors/invalid-images-config.md b/errors/invalid-images-config.md index 5817244392221fe..b409f6056830035 100644 --- a/errors/invalid-images-config.md +++ b/errors/invalid-images-config.md @@ -27,6 +27,10 @@ module.exports = { minimumCacheTTL: 60, // ordered list of acceptable optimized image formats (mime types) formats: ['image/webp'], + // enable dangerous use of SVG images + dangerouslyAllowSVG: false, + // set the Content-Security-Policy header + contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;", }, } ``` diff --git a/lerna.json b/lerna.json index a517697c141b2e9..264e579f1ceb3d9 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.0.11-canary.18" + "version": "12.0.11-canary.19" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index bfaf28f519db33f..733a006f64d4b94 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 08d215f8ab7f72e..a205a69d1dbb128 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.0.11-canary.18", + "@next/eslint-plugin-next": "12.0.11-canary.19", "@rushstack/eslint-patch": "^1.0.8", "@typescript-eslint/parser": "^5.0.0", "eslint-import-resolver-node": "^0.3.4", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index f776c2485ceff3a..ffffceed908f70a 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 25e64cab7382d21..a9b47cce2357f2b 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 5f95a9835b6e098..69f60ffbc7358b4 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 3a9151ee3418d40..668b3b55ca10fdb 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 1600d8aedb0ffac..c212d22d2285846 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 749b71487b03d47..e453865d80f5d85 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 6a204da8d44d42c..347d0c5c2b9e521 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 549509485d9589e..560516330119182 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/Cargo.lock b/packages/next-swc/Cargo.lock index af269fdef7c0c6e..603918b6e73947a 100644 --- a/packages/next-swc/Cargo.lock +++ b/packages/next-swc/Cargo.lock @@ -812,7 +812,7 @@ dependencies = [ "swc_css", "swc_ecma_loader", "swc_ecma_transforms_testing", - "swc_ecmascript 0.114.2", + "swc_ecmascript", "swc_node_base", "swc_stylis", "testing", @@ -839,7 +839,7 @@ dependencies = [ "swc_bundler", "swc_common", "swc_ecma_loader", - "swc_ecmascript 0.114.2", + "swc_ecmascript", "swc_node_base", ] @@ -915,9 +915,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.9.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "opaque-debug" @@ -1589,15 +1589,15 @@ dependencies = [ "serde", "swc_atoms", "swc_common", - "swc_ecmascript 0.112.6", + "swc_ecmascript", "tracing", ] [[package]] name = "swc" -version = "0.126.2" +version = "0.121.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c2373a6f6dddd42719a2d8fcd9989849915ae15691fd1a75f6b04d14a6cab91" +checksum = "e6d2753ff42ccbcf55b444c5b5c75bdf8d711b9c022c6117a1945a5b259721da" dependencies = [ "ahash", "anyhow", @@ -1628,7 +1628,7 @@ dependencies = [ "swc_ecma_transforms_optimization", "swc_ecma_utils", "swc_ecma_visit", - "swc_ecmascript 0.114.2", + "swc_ecmascript", "swc_node_comments", "swc_visit", "tracing", @@ -1646,9 +1646,9 @@ dependencies = [ [[package]] name = "swc_bundler" -version = "0.107.0" +version = "0.105.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b6761f9b57072658a42ff25304a7edc7f8444024726ed27d5861e4644c1ffe" +checksum = "6288db2c327430667c9ab30fb053a76f6dbb4868569ef9833e04d355ef1e1d96" dependencies = [ "ahash", "anyhow", @@ -1711,9 +1711,9 @@ dependencies = [ [[package]] name = "swc_css" -version = "0.85.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f657d1876aa951dabce2be53af58e73f3c6fd61d17f177b647966ad9d77168" +checksum = "75a4e8913ddbf92a39e087996c30a80dfcac5192adc3fb63cd3beabe8975b0c8" dependencies = [ "swc_css_ast", "swc_css_codegen", @@ -1724,9 +1724,9 @@ dependencies = [ [[package]] name = "swc_css_ast" -version = "0.77.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26127ec7150da493706c0a8153cf1ad73fe1f2dd4e010e51ca783a97d4881a44" +checksum = "b0861c74eba5c61ade5c1ef3a14e3e0fd0699f20e5619bbc292c2ac4f9463617" dependencies = [ "is-macro", "serde", @@ -1737,9 +1737,9 @@ dependencies = [ [[package]] name = "swc_css_codegen" -version = "0.82.0" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f7181cd4048b62f2e89e5a26b38c7d2d6bb5cd9080850b8d0278f8525062688" +checksum = "de309d82614f8d3613c27f4ccafbacc1ed524ca5bfd7792387f76314d5131df2" dependencies = [ "auto_impl", "bitflags", @@ -1764,9 +1764,9 @@ dependencies = [ [[package]] name = "swc_css_parser" -version = "0.83.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69ce9cc25996b42c50a0d2312021faf9e2d646a8c5baea6ea17ab7e928ba4bda" +checksum = "ac061b34fb0a3afa4ac5777b705c149f91c2ab29fc5f8463acb2bf8a17e02938" dependencies = [ "bitflags", "lexical", @@ -1777,9 +1777,9 @@ dependencies = [ [[package]] name = "swc_css_utils" -version = "0.74.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee0b4a58cce4b02567f54c079cd7ce3a18bfb79638f81f2197079e7c35e4f749" +checksum = "94cdc01e5631f63f8d4c52545d9a61ed5a6616a2d8d4d4b6235ea2ff779ae80c" dependencies = [ "swc_atoms", "swc_common", @@ -1789,9 +1789,9 @@ dependencies = [ [[package]] name = "swc_css_visit" -version = "0.76.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d4bab1a12ffe359eca6413b09865e27c9e05c0e8d765bebd558d14df31f6e44" +checksum = "ce49ce82798c85e1a8f2a46552b6ef9530868302c333f8b135da3b5c9d5b1ca8" dependencies = [ "swc_atoms", "swc_common", @@ -1862,16 +1862,13 @@ dependencies = [ [[package]] name = "swc_ecma_lints" -version = "0.14.8" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dc7e7d669e28b2df325d9a232f1d74e7b77d2606c04f0f70cc37e38dcf49ad3" +checksum = "a4c9664c8261d32d1dff6df9978c4aa3b0ac686b8bbcab9d4cc8a2f56c9efdfc" dependencies = [ - "ahash", "auto_impl", - "dashmap", "parking_lot", "rayon", - "regex", "serde", "swc_atoms", "swc_common", @@ -1902,9 +1899,9 @@ dependencies = [ [[package]] name = "swc_ecma_minifier" -version = "0.74.1" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "184e0e6337f2a4cfff36e3456e7937846dadf0b47833b7f711654e4acd0a13aa" +checksum = "6541c47325e3b6b2c0a1ecdff32049bc3ae83765eb09e49f532ed4fcbe54a6e7" dependencies = [ "ahash", "indexmap", @@ -1931,9 +1928,9 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "0.88.3" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd30c93f08afdf29226b5695e45aadcc6ce452470cc63ea87a7eb53d29bb02b" +checksum = "016e15f5837f1fb954c7a693a0229fc25cba2982ab9c13773db44ce0e00dc275" dependencies = [ "either", "enum_kind", @@ -1951,9 +1948,9 @@ dependencies = [ [[package]] name = "swc_ecma_preset_env" -version = "0.90.0" +version = "0.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5335f575d5cd4fcefe8bb3c52fa8dc8d59d461f07da43fb2ac6c31689aa88e0f" +checksum = "7ebd2ffd8d26a5d52d86da8d643038da2952e86993998f120554a80e0a64e2b5" dependencies = [ "ahash", "anyhow", @@ -1977,9 +1974,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms" -version = "0.117.0" +version = "0.115.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1fa132c1a736c2c61736958f1102249348a4cc911c7f60e3a6255aa49c1c03e" +checksum = "142a3d2bd7a1d78fd2112a98cb295b7b6aa67c2c590d639650882cd658fc43c9" dependencies = [ "swc_atoms", "swc_common", @@ -2020,9 +2017,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_classes" -version = "0.46.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac8983235c6902879b65dcb1003d4084adf094408c96d94d62d3f33f44c3fa8e" +checksum = "d8fec6a1780299ff1006539b71bed431bde5e48c9773235de4ccc414467ff0f2" dependencies = [ "swc_atoms", "swc_common", @@ -2034,9 +2031,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_compat" -version = "0.70.0" +version = "0.69.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9a64fc99b205b6104a6996832b0006fc059f5aa9fe61d5fb2c3b9f1885b14" +checksum = "c7e1ec45963836c97a27c1c43c316ddfdddeac274aa793223a0a82391ba2304f" dependencies = [ "ahash", "arrayvec 0.7.2", @@ -2072,9 +2069,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_module" -version = "0.78.0" +version = "0.76.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "441616e68981062a1650a923d2c63075021a8178045e2112007a90a157cdb1da" +checksum = "151f5f8fb7bf42d4bbc04e61af0b5fd84e31b1a3014e006f60246b1cac68274e" dependencies = [ "Inflector", "ahash", @@ -2094,9 +2091,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_optimization" -version = "0.87.0" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e074149dd5e969d35a790851b47b0f76700b14fcfda1c05e15751c1458e2dd38" +checksum = "57792864e708f7ba41c4fed8c8b8e2c01dba8da4a44aa43ebb70a60e07e45265" dependencies = [ "ahash", "dashmap", @@ -2117,9 +2114,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_proposal" -version = "0.77.0" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048ac8ea82e02fa9a54b9aa448dc5d15a8e994304364fcd8c4e2f650572c9141" +checksum = "4e0c8f8ad3e3960658e4d7a4a87609b893b2a023f570e45b91f4ebe025845b43" dependencies = [ "either", "serde", @@ -2137,9 +2134,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_react" -version = "0.80.0" +version = "0.78.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb5b7c98597bf41d1503ca4039be5445fd02e7aa381ae520d1c78a8a370f7f5" +checksum = "3d93afe0884dbcb5d4f931d6b2673ba65ad17d0de4d1c88e69f2730f13817739" dependencies = [ "ahash", "base64 0.13.0", @@ -2185,9 +2182,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_typescript" -version = "0.82.0" +version = "0.80.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7859a18a33f751d488fbc1b7a0073fb08c69d794ad1f8daa2da47bfda2d9242" +checksum = "4b136bcb8a598378542393b2e9b51231e23e34b858baa0582aa72e78a2d5fee5" dependencies = [ "serde", "swc_atoms", @@ -2202,9 +2199,9 @@ dependencies = [ [[package]] name = "swc_ecma_utils" -version = "0.65.3" +version = "0.65.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b462ac7dd5340544e7a12965bb7fbbbf9db8b26c1b32159b43c4b2430fed3fc8" +checksum = "a372b01214518c1dbfb9f84d7e08e8e46e2098e7e1f63eb9e9f6f06025ae2863" dependencies = [ "indexmap", "once_cell", @@ -2235,18 +2232,6 @@ name = "swc_ecmascript" version = "0.112.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce38cf2c41ed841d82dbfb1c328379a3ec75d4e4e43900ea8c8ef3c51a44e3cb" -dependencies = [ - "swc_ecma_ast", - "swc_ecma_parser", - "swc_ecma_utils", - "swc_ecma_visit", -] - -[[package]] -name = "swc_ecmascript" -version = "0.114.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e752c12b209c65e203a952186ab2fcefa8021a17a8a393b7d5f410e1fe1a0e87" dependencies = [ "swc_ecma_ast", "swc_ecma_codegen", @@ -2328,9 +2313,9 @@ dependencies = [ [[package]] name = "swc_stylis" -version = "0.81.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cf66bb3ab3e136fb0852c2577824cd19b76f3346d7c5558cfdb782b5f14f6a4" +checksum = "75fd0f4f37579b15bbcd762b0fd1ae3fc6ef29215777b96cbc2bcdfaacd439ab" dependencies = [ "swc_atoms", "swc_common", @@ -2664,7 +2649,7 @@ dependencies = [ "serde_json", "swc", "swc_common", - "swc_ecmascript 0.114.2", + "swc_ecmascript", "tracing", "wasm-bindgen", "wasm-bindgen-futures", diff --git a/packages/next-swc/crates/core/Cargo.toml b/packages/next-swc/crates/core/Cargo.toml index 6e82e60b7a98166..1b43fb3ebc4ccbc 100644 --- a/packages/next-swc/crates/core/Cargo.toml +++ b/packages/next-swc/crates/core/Cargo.toml @@ -16,14 +16,14 @@ pathdiff = "0.2.0" serde = "1" serde_json = "1" styled_components = "0.14.0" -swc = "0.126.2" +swc = "0.121.7" swc_atoms = "0.2.7" swc_common = { version = "0.17.0", features = ["concurrent", "sourcemap"] } -swc_css = "0.85.0" +swc_css = "0.46.0" swc_ecma_loader = { version = "0.28.0", features = ["node", "lru"] } -swc_ecmascript = { version = "0.114.2", features = ["codegen", "minifier", "optimization", "parser", "react", "transforms", "typescript", "utils", "visit"] } +swc_ecmascript = { version = "0.112.6", features = ["codegen", "minifier", "optimization", "parser", "react", "transforms", "typescript", "utils", "visit"] } swc_node_base = "0.5.1" -swc_stylis = "0.81.0" +swc_stylis = "0.43.0" tracing = {version = "0.1.28", features = ["release_max_level_off"]} regex = "1.5" diff --git a/packages/next-swc/crates/core/src/styled_jsx/transform_css.rs b/packages/next-swc/crates/core/src/styled_jsx/transform_css.rs index d25cd05e634967a..dcf00d73bf56b7e 100644 --- a/packages/next-swc/crates/core/src/styled_jsx/transform_css.rs +++ b/packages/next-swc/crates/core/src/styled_jsx/transform_css.rs @@ -21,7 +21,7 @@ use tracing::{debug, trace}; use super::{hash_string, string_literal_expr, LocalStyle}; pub fn transform_css( - _cm: Arc, + cm: Arc, style_info: &LocalStyle, is_global: bool, class_name: &Option, @@ -33,6 +33,7 @@ pub fn transform_css( style_info.css_span.lo, style_info.css_span.hi, ParserConfig { + parse_values: false, allow_wrong_line_comments: true, }, // We ignore errors because we inject placeholders for expressions which is @@ -61,6 +62,7 @@ pub fn transform_css( }; // ? Do we need to support optionally prefixing? ss.visit_mut_with(&mut prefixer()); + ss.visit_mut_with(&mut CssPlaceholderFixer { cm }); ss.visit_mut_with(&mut Namespacer { class_name: match class_name { Some(s) => s.clone(), @@ -129,6 +131,48 @@ fn read_number(s: &str) -> (usize, usize) { unreachable!("read_number(`{}`) is invalid because it is empty", s) } +/// This fixes invalid css which is created from interpolated expressions. +/// +/// `__styled-jsx-placeholder-` is handled at here. +struct CssPlaceholderFixer { + cm: Arc, +} + +impl VisitMut for CssPlaceholderFixer { + fn visit_mut_media_query(&mut self, q: &mut MediaQuery) { + q.visit_mut_children_with(self); + + match q { + MediaQuery::Ident(q) => { + if !q.raw.starts_with("__styled-jsx-placeholder-") { + return; + } + // We need to support both of @media ($breakPoint) {} and @media $queryString {} + // This is complex because @media (__styled-jsx-placeholder-0__) {} is valid + // while @media __styled-jsx-placeholder-0__ {} is not + // + // So we check original source code to determine if we should inject + // parenthesis. + + // TODO(kdy1): Avoid allocation. + // To remove allocation, we should patch swc_common to provide a way to get + // source code without allocation. + // + // + // We need + // + // fn with_source_code (self: &mut Self, f: impl FnOnce(&str) -> Ret) -> _ {} + if let Ok(source) = self.cm.span_to_snippet(q.span) { + if source.starts_with('(') { + q.raw = format!("({})", &q.value).into(); + } + } + } + _ => {} + } + } +} + struct Namespacer { class_name: String, is_global: bool, @@ -185,7 +229,9 @@ impl VisitMut for Namespacer { } ComplexSelectorChildren::Combinator(v) => match v.value { CombinatorValue::Descendant => {} - _ => { + CombinatorValue::NextSibling + | CombinatorValue::Child + | CombinatorValue::LaterSibling => { combinator = Some(v.clone()); new_selectors.push(sel); @@ -205,22 +251,23 @@ impl Namespacer { ) -> Result, Error> { let mut pseudo_index = None; - let empty_tokens = vec![]; + let empty_tokens = Tokens { + span: node.span, + tokens: vec![], + }; let mut arg_tokens; for (i, selector) in node.subclass_selectors.iter().enumerate() { let (name, args) = match selector { SubclassSelector::PseudoClass(PseudoClassSelector { name, children, .. }) => { - arg_tokens = children - .iter() - .flatten() - .flat_map(|v| match v { - PseudoSelectorChildren::Nth(v) => nth_to_tokens(v).tokens, - PseudoSelectorChildren::PreservedToken(v) => vec![v.clone()], - }) - .collect::>(); - - (name, &arg_tokens) + match children { + Some(PseudoSelectorChildren::Nth(v)) => { + arg_tokens = nth_to_tokens(&v); + (name, &arg_tokens) + } + Some(PseudoSelectorChildren::Tokens(v)) => (name, v), + None => (name, &empty_tokens), + } } SubclassSelector::PseudoElement(PseudoElementSelector { name, children, .. @@ -233,19 +280,9 @@ impl Namespacer { // One off global selector if &name.value == "global" { - let args = args.clone(); - let mut args = { - let lo = args.first().map(|v| v.span.lo).unwrap_or(BytePos(0)); - let hi = args.last().map(|v| v.span.hi).unwrap_or(BytePos(0)); - - Tokens { - span: Span::new(lo, hi, Default::default()), - tokens: args, - } - }; - let block_tokens = get_block_tokens(&args); let mut front_tokens = get_front_selector_tokens(&args); + let mut args = args.clone(); front_tokens.extend(args.tokens); front_tokens.extend(block_tokens); args.tokens = front_tokens; @@ -254,6 +291,7 @@ impl Namespacer { let x: ComplexSelector = parse_tokens( &args, ParserConfig { + parse_values: false, allow_wrong_line_comments: true, }, // TODO(kdy1): We might be able to report syntax errors. @@ -484,6 +522,7 @@ fn nth_to_tokens(nth: &Nth) -> Tokens { let mut lexer = swc_css::parser::lexer::Lexer::new( StringInput::new(&s, nth.span.lo, nth.span.hi), ParserConfig { + parse_values: false, allow_wrong_line_comments: true, ..Default::default() }, diff --git a/packages/next-swc/crates/core/tests/errors/styled-jsx/ts-with-css-resolve/output.js b/packages/next-swc/crates/core/tests/errors/styled-jsx/ts-with-css-resolve/output.js index 6fbd823e7814ad9..135a868443bee87 100644 --- a/packages/next-swc/crates/core/tests/errors/styled-jsx/ts-with-css-resolve/output.js +++ b/packages/next-swc/crates/core/tests/errors/styled-jsx/ts-with-css-resolve/output.js @@ -1,5 +1,5 @@ import _JSXStyle from "styled-jsx/style"; export default { - styles: <_JSXStyle id={"71f03d42ea0ec6"}>{".container.jsx-71f03d42ea0ec6{background:#000;color:white;font-weight:700;height:100px}"}, + styles: <_JSXStyle id={"71f03d42ea0ec6"}>{".container.jsx-71f03d42ea0ec6{background:#000;\ncolor:white;\nfont-weight:700;\nheight:100px}"}, className: "jsx-71f03d42ea0ec6" -}; +}; \ No newline at end of file diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/css-selector-after-pseudo/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/css-selector-after-pseudo/output.js index adc37567bc9bc45..6cb37534c641bbe 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/css-selector-after-pseudo/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/css-selector-after-pseudo/output.js @@ -4,7 +4,7 @@ function NavigationItem({ active , className }) { active }, className, "navigation-item") || "")}> - <_JSXStyle id={"2342aae4628612c6"}>{".navigation-item.jsx-2342aae4628612c6 a::after{content:attr(data-text);content:attr(data-text)/\"\"}"} + <_JSXStyle id={"2342aae4628612c6"}>{".navigation-item.jsx-2342aae4628612c6 a::after{content:attr(data-text);\ncontent: attr(data-text) / ''}"}
; } diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/expressions/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/expressions/output.js index 5822f4fe70aa354..ea1779a5ca0e9f0 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/expressions/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/expressions/output.js @@ -51,7 +51,8 @@ export default (({ display })=>
test

- <_JSXStyle id={"6116059e04f3bff7"}>{`p.${color}.jsx-1ada4ad4dab7822f{color:${otherColor};display:${obj.display}}`} + <_JSXStyle id={"6116059e04f3bff7"}>{`p.${color}.jsx-1ada4ad4dab7822f{color:${otherColor}; +display:${obj.display}}`} <_JSXStyle id={"94239b6d6b42c9b5"}>{"p.jsx-1ada4ad4dab7822f{color:red}"} @@ -73,11 +74,16 @@ export default (({ display })=>
{`p.__jsx-style-dynamic-selector{color:${darken(color) + 2}}`} - <_JSXStyle id={"4e4be2da62837c76"}>{`@media(min-width:${mediumScreen}){p.jsx-1ada4ad4dab7822f{color:green}p.jsx-1ada4ad4dab7822f{color:${`red`}}}p.jsx-1ada4ad4dab7822f{color:red}`} + <_JSXStyle id={"4e4be2da62837c76"}>{`@media (min-width:${mediumScreen}) {p.jsx-1ada4ad4dab7822f{color:green} +p.jsx-1ada4ad4dab7822f{color:${`red`}}} +p.jsx-1ada4ad4dab7822f{color:red}`} - <_JSXStyle id={"27040f0829fb73d4"}>{`p.jsx-1ada4ad4dab7822f{-webkit-animation-duration:${animationDuration};animation-duration:${animationDuration}}`} + <_JSXStyle id={"27040f0829fb73d4"}>{`p.jsx-1ada4ad4dab7822f{-webkit-animation-duration:${animationDuration}; +animation-duration:${animationDuration}}`} - <_JSXStyle id={"3e72d735e703a530"}>{`p.jsx-1ada4ad4dab7822f{-webkit-animation:${animationDuration} forwards ${animationName};animation:${animationDuration} forwards ${animationName}}div.jsx-1ada4ad4dab7822f{background:${color}}`} + <_JSXStyle id={"3e72d735e703a530"}>{`p.jsx-1ada4ad4dab7822f{-webkit-animation:${animationDuration} forwards ${animationName}; +animation:${animationDuration} forwards ${animationName}} +div.jsx-1ada4ad4dab7822f{background:${color}}`} diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/external-stylesheet/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/external-stylesheet/output.js index e0304b413fd0af4..7dc7df9b4c8d786 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/external-stylesheet/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/external-stylesheet/output.js @@ -14,7 +14,7 @@ export default (()=>
woot
- <_JSXStyle id={"bee92b62eadf8a14"}>{"p.jsx-bee92b62eadf8a14{color:red}div.jsx-bee92b62eadf8a14{color:green}"} + <_JSXStyle id={"bee92b62eadf8a14"}>{"p.jsx-bee92b62eadf8a14{color:red}\ndiv.jsx-bee92b62eadf8a14{color:green}"} <_JSXStyle id={styles.__hash}>{styles} @@ -30,7 +30,7 @@ export const Test = ()=>
woot
- <_JSXStyle id={"bee92b62eadf8a14"}>{"p.jsx-bee92b62eadf8a14{color:red}div.jsx-bee92b62eadf8a14{color:green}"} + <_JSXStyle id={"bee92b62eadf8a14"}>{"p.jsx-bee92b62eadf8a14{color:red}\ndiv.jsx-bee92b62eadf8a14{color:green}"}
; diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/fragment/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/fragment/output.js index aefcddc43fcb714..dda9c2b5fc7c534 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/fragment/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/fragment/output.js @@ -28,7 +28,7 @@ export default (()=><> - <_JSXStyle id={"6dd5f97e085c0297"}>{"p.jsx-6dd5f97e085c0297{color:cyan}.foo.jsx-6dd5f97e085c0297{font-size:18px;color:hotpink}#head.jsx-6dd5f97e085c0297{text-decoration:underline}"} + <_JSXStyle id={"6dd5f97e085c0297"}>{"p.jsx-6dd5f97e085c0297{color:cyan}\n.foo.jsx-6dd5f97e085c0297{font-size:18px;\ncolor:hotpink}\n#head.jsx-6dd5f97e085c0297{text-decoration:underline}"} ); diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/global/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/global/output.js index 2ec88553ec8d757..7eab66c441b5a97 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/global/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/global/output.js @@ -1,7 +1,7 @@ import _JSXStyle from "styled-jsx/style"; const Test = ()=>
- <_JSXStyle id={"d47d6adadf14e957"}>{"body{color:red}:hover{color:red;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-animation:foo 1s ease-out;animation:foo 1s ease-out}div a{display:none}[data-test]>div{color:red}"} + <_JSXStyle id={"d47d6adadf14e957"}>{"body{color:red}\n:hover{color:red;\ndisplay:-webkit-box;\ndisplay:-webkit-flex;\ndisplay:-ms-flexbox;\ndisplay:flex;\n-webkit-animation:foo 1s ease-out;\nanimation:foo 1s ease-out}\ndiv a{display:none}\n[data-test]>div{color:red}"}
; diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/issue-30480/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/issue-30480/output.js index f36b6e2e7383719..d91b5759a137084 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/issue-30480/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/issue-30480/output.js @@ -10,7 +10,7 @@ export default (({ breakPoint })=>
{`@media(${breakPoint}){}`} + ]}>{`@media (${breakPoint}) {}`}
); diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/issue-30570/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/issue-30570/output.js index ac9cfafc42458f3..fec5cf3680648f9 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/issue-30570/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/issue-30570/output.js @@ -6,7 +6,7 @@ export default function IndexPage() { - <_JSXStyle id={"bbdada4ef17d18ef"}>{"@supports(display:flex){h1{color:hotpink}}"} + <_JSXStyle id={"bbdada4ef17d18ef"}>{"@supports (display:flex) {h1{color:hotpink}}"}
; }; diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/issue-31562-interpolation-in-mdea/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/issue-31562-interpolation-in-mdea/output.js index ac5394ea192a852..fb59ef207106321 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/issue-31562-interpolation-in-mdea/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/issue-31562-interpolation-in-mdea/output.js @@ -36,7 +36,10 @@ export default class { Typography.base.size.mediumPlus, Target.largePlus, Typography.base.size.largePlus - ]}>{`html{font-size:${Typography.base.size.default};line-height:${Typography.base.lineHeight}}@media ${Target.mediumPlus}{html{font-size:${Typography.base.size.mediumPlus}}}@media ${Target.largePlus}{html{font-size:${Typography.base.size.largePlus}}}`} + ]}>{`html{font-size:${Typography.base.size.default}; +line-height:${Typography.base.lineHeight}} +@media ${Target.mediumPlus} {html{font-size:${Typography.base.size.mediumPlus}}} +@media ${Target.largePlus} {html{font-size:${Typography.base.size.largePlus}}}`}
; } diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/styles/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/styles/output.js index 7b61c0b7ec131ea..415058e5691e55a 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/styles/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/styles/output.js @@ -11,18 +11,21 @@ export const uh = bar; export const foo = new String(`div.jsx-945eaa83250ed332{color:${color}}`); foo.__hash = "945eaa83250ed332"; ({ - styles: <_JSXStyle id={"c107a919a5b2943d"}>{`div.jsx-c107a919a5b2943d{color:${colors.green.light}}a.jsx-c107a919a5b2943d{color:red}`}, + styles: <_JSXStyle id={"c107a919a5b2943d"}>{`div.jsx-c107a919a5b2943d{color:${colors.green.light}} +a.jsx-c107a919a5b2943d{color:red}`}, className: "jsx-c107a919a5b2943d" }); const b = { - styles: <_JSXStyle id={"c107a919a5b2943d"}>{`div.jsx-c107a919a5b2943d{color:${colors.green.light}}a.jsx-c107a919a5b2943d{color:red}`}, + styles: <_JSXStyle id={"c107a919a5b2943d"}>{`div.jsx-c107a919a5b2943d{color:${colors.green.light}} +a.jsx-c107a919a5b2943d{color:red}`}, className: "jsx-c107a919a5b2943d" }; const dynamic = (colors1)=>{ const b = { styles: <_JSXStyle id={"60132422fc87f1d1"} dynamic={[ colors1.green.light - ]}>{`div.__jsx-style-dynamic-selector{color:${colors1.green.light}}a.__jsx-style-dynamic-selector{color:red}`}, + ]}>{`div.__jsx-style-dynamic-selector{color:${colors1.green.light}} +a.__jsx-style-dynamic-selector{color:red}`}, className: _JSXStyle.dynamic([ [ "60132422fc87f1d1", @@ -34,6 +37,7 @@ const dynamic = (colors1)=>{ }; }; export default { - styles: <_JSXStyle id={"e5da8dd7ff5c7f39"}>{`div.jsx-e5da8dd7ff5c7f39{font-size:3em}p.jsx-e5da8dd7ff5c7f39{color:${color}}`}, + styles: <_JSXStyle id={"e5da8dd7ff5c7f39"}>{`div.jsx-e5da8dd7ff5c7f39{font-size:3em} +p.jsx-e5da8dd7ff5c7f39{color:${color}}`}, className: "jsx-e5da8dd7ff5c7f39" }; diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/too-many/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/too-many/output.js index fd67a8dec05a8c2..00ff7acd83a698f 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/too-many/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/too-many/output.js @@ -43,7 +43,21 @@ export const Red = ({ Component ="button" })=>{ e13, e14, e15 - ]}>{`.button.__jsx-style-dynamic-selector{--button-1:${e1};--button-2:${e2};--button-3:${e3};--button-4:${e4};--button-5:${e5};--button-6:${e6};--button-7:${e7};--button-8:${e8};--button-9:${e9};--button-10:${e10};--button-11:${e11};--button-12:${e12};--button-13:${e13};--button-14:${e14};--button-15:${e15}}`} + ]}>{`.button.__jsx-style-dynamic-selector{--button-1: ${e1}; +--button-2: ${e2}; +--button-3: ${e3}; +--button-4: ${e4}; +--button-5: ${e5}; +--button-6: ${e6}; +--button-7: ${e7}; +--button-8: ${e8}; +--button-9: ${e9}; +--button-10: ${e10}; +--button-11: ${e11}; +--button-12: ${e12}; +--button-13: ${e13}; +--button-14: ${e14}; +--button-15: ${e15}}`} ; }; diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-escape-1/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-escape-1/output.js index b12af6f02d53d18..7b9b2f69a80329b 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-escape-1/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-escape-1/output.js @@ -5,7 +5,7 @@ export default class {

test

- <_JSXStyle id={"1f6cef12199c3a8f"}>{"p.jsx-1f6cef12199c3a8f{content:\"`\"}"} + <_JSXStyle id={"1f6cef12199c3a8f"}>{"p.jsx-1f6cef12199c3a8f{content:'`'}"} ; } diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-escape-2/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-escape-2/output.js index c94ca5493d06c47..3e3ed2489c6705a 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-escape-2/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-escape-2/output.js @@ -11,7 +11,8 @@ export default function Home({ fontFamily }) { <_JSXStyle id={"f804e2f486b6ac13"} dynamic={[ fontFamily - ]}>{`body{font-family:${fontFamily}}code:before,code:after{content:"\`"}`} + ]}>{`body{font-family:${fontFamily}} +code:before, code:after{content:'\`'}`} ; }; diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-1-as-property/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-1-as-property/output.js index 28d29b34b19665d..9d93281ced13fd4 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-1-as-property/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-1-as-property/output.js @@ -21,7 +21,7 @@ export default class { <_JSXStyle id={"e359801ddd3b3cb6"} dynamic={[ inputSize ? "height: calc(2 * var(--a)) !important;" : "" - ]}>{`@media only screen{a.__jsx-style-dynamic-selector{${inputSize ? "height: calc(2 * var(--a)) !important;" : ""} + ]}>{`@media only screen {a.__jsx-style-dynamic-selector{${inputSize ? "height: calc(2 * var(--a)) !important;" : ""} }}`} ; diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-2-as-part-of-value/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-2-as-part-of-value/output.js index 7c0c59d4ac651a1..bc25a6c5235b41e 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-2-as-part-of-value/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-2-as-part-of-value/output.js @@ -27,7 +27,8 @@ export default class { a[b], -1 * (c || 0), d - ]}>{`.a:hover .b.__jsx-style-dynamic-selector{a:${a[b]}px!important;b:translate3d(0,${-1 * (c || 0)}px,-${d}px)scale(1)!important}`} + ]}>{`.a:hover .b.__jsx-style-dynamic-selector{a:${a[b]}px!important; +b:translate3d(0, ${-1 * (c || 0)}px, -${d}px) scale(1)!important}`} ; } diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-3-as-value/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-3-as-value/output.js index 754e53aa0330908..f311c3526881348 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-3-as-value/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-3-as-value/output.js @@ -21,7 +21,7 @@ export default class { <_JSXStyle id={"4ca4ef3595473f53"} dynamic={[ a - ]}>{`@media only screen{a.__jsx-style-dynamic-selector{color:${a}}}`} + ]}>{`@media only screen {a.__jsx-style-dynamic-selector{color:${a}}}`} ; } diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-4-as-part-of-value-in-multiple/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-4-as-part-of-value-in-multiple/output.js index 8f9e67c31304ac9..4683d8c24306222 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-4-as-part-of-value-in-multiple/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-4-as-part-of-value-in-multiple/output.js @@ -24,7 +24,9 @@ export default class { <_JSXStyle id={"97886c1e9511aafa"} dynamic={[ a || "var(--c)", b || "inherit" - ]}>{`.a:hover .b.__jsx-style-dynamic-selector{display:inline-block;padding:0 ${a || "var(--c)"};color:${b || "inherit"}}`} + ]}>{`.a:hover .b.__jsx-style-dynamic-selector{display:inline-block; +padding:0 ${a || "var(--c)"}; +color:${b || "inherit"}}`} ; } diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-5-values-of-multiple-properties/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-5-values-of-multiple-properties/output.js index 898bc9e3d60aa32..e009c13a7456165 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-5-values-of-multiple-properties/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/tpl-placeholder-5-values-of-multiple-properties/output.js @@ -24,7 +24,8 @@ export default class { <_JSXStyle id={"bcc606c168bcd197"} dynamic={[ a ? "100%" : "200px", b ? "0" : "8px 20px" - ]}>{`.item.__jsx-style-dynamic-selector{max-width:${a ? "100%" : "200px"};padding:${b ? "0" : "8px 20px"}}`} + ]}>{`.item.__jsx-style-dynamic-selector{max-width:${a ? "100%" : "200px"}; +padding:${b ? "0" : "8px 20px"}}`} ; } diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-complex-selector/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-complex-selector/output.js index 5f2002467dea31c..a6480c2fb787d9f 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-complex-selector/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-complex-selector/output.js @@ -3,7 +3,7 @@ export default (()=>

test

- <_JSXStyle id={"713499aa363d6373"}>{"p.jsx-713499aa363d6373 a.jsx-713499aa363d6373 span.jsx-713499aa363d6373{color:red}p.jsx-713499aa363d6373 span{background:blue}p.jsx-713499aa363d6373 a[title=\"'w ' ' t'\"].jsx-713499aa363d6373{margin:auto}p.jsx-713499aa363d6373 span:not(.test){color:green}p.jsx-713499aa363d6373,h1.jsx-713499aa363d6373{color:blue;-webkit-animation:hahaha 3s ease forwards infinite;animation:hahaha 3s ease forwards infinite;-webkit-animation-name:hahaha;animation-name:hahaha;animation-delay:100ms}p.jsx-713499aa363d6373{-webkit-animation:hahaha 1s,hehehe 2s;animation:hahaha 1s,hehehe 2s}p.jsx-713499aa363d6373:hover{color:red}p.jsx-713499aa363d6373::before{color:red}.jsx-713499aa363d6373:hover{color:red}.jsx-713499aa363d6373::before{color:red}.jsx-713499aa363d6373:hover p.jsx-713499aa363d6373{color:red}p.jsx-713499aa363d6373+a.jsx-713499aa363d6373{color:red}p.jsx-713499aa363d6373~a.jsx-713499aa363d6373{color:red}p.jsx-713499aa363d6373>a.jsx-713499aa363d6373{color:red}@keyframes hahaha{from{top:0}to{top:100}}@keyframes hehehe{from{left:0}to{left:100}}@media(min-width:500px){.test.jsx-713499aa363d6373{color:red}}.test.jsx-713499aa363d6373{display:block}.inline-flex.jsx-713499aa363d6373{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex}.flex.jsx-713499aa363d6373{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.test.jsx-713499aa363d6373{box-shadow:0 0 10px black,inset 0 0 5px black}.test[title=\",\"].jsx-713499aa363d6373{display:inline-block}.test.is-status.jsx-713499aa363d6373 .test.jsx-713499aa363d6373{color:red}.a-selector.jsx-713499aa363d6373:hover,.a-selector.jsx-713499aa363d6373:focus{outline:none}"} + <_JSXStyle id={"713499aa363d6373"}>{"p.jsx-713499aa363d6373 a.jsx-713499aa363d6373 span.jsx-713499aa363d6373{color:red}\np.jsx-713499aa363d6373 span{background:blue}\np.jsx-713499aa363d6373 a[title=\"'w ' ' t'\"].jsx-713499aa363d6373{margin:auto}\np.jsx-713499aa363d6373 span:not(.test){color:green}\np.jsx-713499aa363d6373, h1.jsx-713499aa363d6373{color:blue;\n-webkit-animation:hahaha 3s ease forwards infinite;\nanimation:hahaha 3s ease forwards infinite;\n-webkit-animation-name:hahaha;\nanimation-name:hahaha;\nanimation-delay:100ms}\np.jsx-713499aa363d6373{-webkit-animation:hahaha 1s, hehehe 2s;\nanimation:hahaha 1s, hehehe 2s}\np.jsx-713499aa363d6373:hover{color:red}\np.jsx-713499aa363d6373::before{color:red}\n.jsx-713499aa363d6373:hover{color:red}\n.jsx-713499aa363d6373::before{color:red}\n.jsx-713499aa363d6373:hover p.jsx-713499aa363d6373{color:red}\np.jsx-713499aa363d6373+a.jsx-713499aa363d6373{color:red}\np.jsx-713499aa363d6373~a.jsx-713499aa363d6373{color:red}\np.jsx-713499aa363d6373>a.jsx-713499aa363d6373{color:red}\n@keyframes hahaha {from {top:0}to {top:100}}\n@keyframes hehehe {from {left:0}to {left:100}}\n@media (min-width:500px) {.test.jsx-713499aa363d6373{color:red}}\n.test.jsx-713499aa363d6373{display:block}\n.inline-flex.jsx-713499aa363d6373{display:-webkit-inline-box;\ndisplay:-webkit-inline-flex;\ndisplay:-ms-inline-flexbox;\ndisplay:inline-flex}\n.flex.jsx-713499aa363d6373{display:-webkit-box;\ndisplay:-webkit-flex;\ndisplay:-ms-flexbox;\ndisplay:flex}\n.test.jsx-713499aa363d6373{box-shadow:0 0 10px black, inset 0 0 5px black}\n.test[title=\",\"].jsx-713499aa363d6373{display:inline-block}\n.test.is-status.jsx-713499aa363d6373 .test.jsx-713499aa363d6373{color:red}\n.a-selector.jsx-713499aa363d6373:hover, .a-selector.jsx-713499aa363d6373:focus{outline:none}"}
); diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-global/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-global/output.js index b9405bfa115039c..e8ab9d15554867b 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-global/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-global/output.js @@ -3,7 +3,7 @@ export default (()=>

test

- <_JSXStyle id={"53fd644ab080300c"}>{"html.jsx-53fd644ab080300c{background-image:linear-gradient(0deg,rgba(255,255,255,.8),rgba(255,255,255,.8)),url(/static/background.svg)}p{color:blue}p{color:blue}p,a.jsx-53fd644ab080300c{color:blue}.foo+a{color:red}body{font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Helvetica,Arial,sans-serif}"} + <_JSXStyle id={"53fd644ab080300c"}>{"html.jsx-53fd644ab080300c{background-image:linear-gradient(0deg, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)), url(/static/background.svg)}\np{color:blue}\np{color:blue}\np, a.jsx-53fd644ab080300c{color:blue}\n.foo+a{color:red}\nbody{font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif}"}
); diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-media-query/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-media-query/output.js index c5a6b455fb26a8c..abc84ac0f354d0e 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-media-query/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-media-query/output.js @@ -3,7 +3,7 @@ export default (()=>

test

- <_JSXStyle id={"1f7963ae04c6466a"}>{"@media(min-width:1px)and (max-width:768px){[class*=\"grid__col--\"].jsx-1f7963ae04c6466a{margin-top:12px;margin-bottom:12px}}@media(max-width:64em){.test.jsx-1f7963ae04c6466a{margin-bottom:1em}@supports(-moz-appearance:none)and (display:contents){.test.jsx-1f7963ae04c6466a{margin-bottom:2rem}}}"} + <_JSXStyle id={"1f7963ae04c6466a"}>{"@media (min-width:1px) and (max-width:768px) {[class*='grid__col--'].jsx-1f7963ae04c6466a{margin-top:12px;\nmargin-bottom:12px}}\n@media (max-width:64em) {.test.jsx-1f7963ae04c6466a{margin-bottom:1em}\n@supports (-moz-appearance:none) and (display:contents) {.test.jsx-1f7963ae04c6466a{margin-bottom:2rem}}}"}
); diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-normal/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-normal/output.js index 98a03ea47b4ca77..9c81fa9facdf808 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-normal/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css-normal/output.js @@ -3,7 +3,7 @@ export default (()=>

test

- <_JSXStyle id={"1a19bb4817c105dd"}>{"p.jsx-1a19bb4817c105dd{color:red}p.jsx-1a19bb4817c105dd{color:red}*.jsx-1a19bb4817c105dd{color:blue}[href=\"woot\"].jsx-1a19bb4817c105dd{color:red}"} + <_JSXStyle id={"1a19bb4817c105dd"}>{"p.jsx-1a19bb4817c105dd{color:red}\np.jsx-1a19bb4817c105dd{color:red}\n*.jsx-1a19bb4817c105dd{color:blue}\n[href=\"woot\"].jsx-1a19bb4817c105dd{color:red}"}
); diff --git a/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css/output.js b/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css/output.js index 7a279450b965d13..ddefde312281627 100644 --- a/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css/output.js +++ b/packages/next-swc/crates/core/tests/fixture/styled-jsx/transform-css/output.js @@ -3,7 +3,7 @@ export default (()=>

test

- <_JSXStyle id={"768337a97aceabd1"}>{"html.jsx-768337a97aceabd1{background-image:linear-gradient(0deg,rgba(255,255,255,.8),rgba(255,255,255,.8)),url(/static/background.svg)}p{color:blue}p{color:blue}p,a.jsx-768337a97aceabd1{color:blue}.foo+a{color:red}body{font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Helvetica,Arial,sans-serif}p.jsx-768337a97aceabd1{color:red}p.jsx-768337a97aceabd1{color:red}*.jsx-768337a97aceabd1{color:blue}[href=\"woot\"].jsx-768337a97aceabd1{color:red}p.jsx-768337a97aceabd1 a.jsx-768337a97aceabd1 span.jsx-768337a97aceabd1{color:red}p.jsx-768337a97aceabd1 span{background:blue}p.jsx-768337a97aceabd1 a[title=\"'w ' ' t'\"].jsx-768337a97aceabd1{margin:auto}p.jsx-768337a97aceabd1 span:not(.test){color:green}p.jsx-768337a97aceabd1,h1.jsx-768337a97aceabd1{color:blue;-webkit-animation:hahaha 3s ease forwards infinite;animation:hahaha 3s ease forwards infinite;-webkit-animation-name:hahaha;animation-name:hahaha;animation-delay:100ms}p.jsx-768337a97aceabd1{-webkit-animation:hahaha 1s,hehehe 2s;animation:hahaha 1s,hehehe 2s}p.jsx-768337a97aceabd1:hover{color:red}p.jsx-768337a97aceabd1::before{color:red}.jsx-768337a97aceabd1:hover{color:red}.jsx-768337a97aceabd1::before{color:red}.jsx-768337a97aceabd1:hover p.jsx-768337a97aceabd1{color:red}p.jsx-768337a97aceabd1+a.jsx-768337a97aceabd1{color:red}p.jsx-768337a97aceabd1~a.jsx-768337a97aceabd1{color:red}p.jsx-768337a97aceabd1>a.jsx-768337a97aceabd1{color:red}@keyframes hahaha{from{top:0}to{top:100}}@keyframes hehehe{from{left:0}to{left:100}}@media(min-width:500px){.test.jsx-768337a97aceabd1{color:red}}.test.jsx-768337a97aceabd1{display:block}.inline-flex.jsx-768337a97aceabd1{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex}.flex.jsx-768337a97aceabd1{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.test.jsx-768337a97aceabd1{box-shadow:0 0 10px black,inset 0 0 5px black}.test[title=\",\"].jsx-768337a97aceabd1{display:inline-block}.test.is-status.jsx-768337a97aceabd1 .test.jsx-768337a97aceabd1{color:red}.a-selector.jsx-768337a97aceabd1:hover,.a-selector.jsx-768337a97aceabd1:focus{outline:none}@media(min-width:1px)and (max-width:768px){[class*=\"grid__col--\"].jsx-768337a97aceabd1{margin-top:12px;margin-bottom:12px}}@media(max-width:64em){.test.jsx-768337a97aceabd1{margin-bottom:1em}@supports(-moz-appearance:none)and (display:contents){.test.jsx-768337a97aceabd1{margin-bottom:2rem}}}"} + <_JSXStyle id={"768337a97aceabd1"}>{"html.jsx-768337a97aceabd1{background-image:linear-gradient(0deg, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)), url(/static/background.svg)}\np{color:blue}\np{color:blue}\np, a.jsx-768337a97aceabd1{color:blue}\n.foo+a{color:red}\nbody{font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif}\np.jsx-768337a97aceabd1{color:red}\np.jsx-768337a97aceabd1{color:red}\n*.jsx-768337a97aceabd1{color:blue}\n[href=\"woot\"].jsx-768337a97aceabd1{color:red}\np.jsx-768337a97aceabd1 a.jsx-768337a97aceabd1 span.jsx-768337a97aceabd1{color:red}\np.jsx-768337a97aceabd1 span{background:blue}\np.jsx-768337a97aceabd1 a[title=\"'w ' ' t'\"].jsx-768337a97aceabd1{margin:auto}\np.jsx-768337a97aceabd1 span:not(.test){color:green}\np.jsx-768337a97aceabd1, h1.jsx-768337a97aceabd1{color:blue;\n-webkit-animation:hahaha 3s ease forwards infinite;\nanimation:hahaha 3s ease forwards infinite;\n-webkit-animation-name:hahaha;\nanimation-name:hahaha;\nanimation-delay:100ms}\np.jsx-768337a97aceabd1{-webkit-animation:hahaha 1s, hehehe 2s;\nanimation:hahaha 1s, hehehe 2s}\np.jsx-768337a97aceabd1:hover{color:red}\np.jsx-768337a97aceabd1::before{color:red}\n.jsx-768337a97aceabd1:hover{color:red}\n.jsx-768337a97aceabd1::before{color:red}\n.jsx-768337a97aceabd1:hover p.jsx-768337a97aceabd1{color:red}\np.jsx-768337a97aceabd1+a.jsx-768337a97aceabd1{color:red}\np.jsx-768337a97aceabd1~a.jsx-768337a97aceabd1{color:red}\np.jsx-768337a97aceabd1>a.jsx-768337a97aceabd1{color:red}\n@keyframes hahaha {from {top:0}to {top:100}}\n@keyframes hehehe {from {left:0}to {left:100}}\n@media (min-width:500px) {.test.jsx-768337a97aceabd1{color:red}}\n.test.jsx-768337a97aceabd1{display:block}\n.inline-flex.jsx-768337a97aceabd1{display:-webkit-inline-box;\ndisplay:-webkit-inline-flex;\ndisplay:-ms-inline-flexbox;\ndisplay:inline-flex}\n.flex.jsx-768337a97aceabd1{display:-webkit-box;\ndisplay:-webkit-flex;\ndisplay:-ms-flexbox;\ndisplay:flex}\n.test.jsx-768337a97aceabd1{box-shadow:0 0 10px black, inset 0 0 5px black}\n.test[title=\",\"].jsx-768337a97aceabd1{display:inline-block}\n.test.is-status.jsx-768337a97aceabd1 .test.jsx-768337a97aceabd1{color:red}\n.a-selector.jsx-768337a97aceabd1:hover, .a-selector.jsx-768337a97aceabd1:focus{outline:none}\n@media (min-width:1px) and (max-width:768px) {[class*='grid__col--'].jsx-768337a97aceabd1{margin-top:12px;\nmargin-bottom:12px}}\n@media (max-width:64em) {.test.jsx-768337a97aceabd1{margin-bottom:1em}\n@supports (-moz-appearance:none) and (display:contents) {.test.jsx-768337a97aceabd1{margin-bottom:2rem}}}"}
); diff --git a/packages/next-swc/crates/core/tests/full/example/output.js b/packages/next-swc/crates/core/tests/full/example/output.js index e0a9c88dd80fa5b..ebba00c28d0bc90 100644 --- a/packages/next-swc/crates/core/tests/full/example/output.js +++ b/packages/next-swc/crates/core/tests/full/example/output.js @@ -1,9 +1,9 @@ -function a(a, b) { +import a from "other"; +function b(a, b) { (null == b || b > a.length) && (b = a.length); for(var c = 0, d = new Array(b); c < b; c++)d[c] = a[c]; return d; } -import b from "other"; (function(a, c) { return (function(a) { if (Array.isArray(a)) return a; @@ -24,17 +24,17 @@ import b from "other"; } return g; } - })(a, c) || (function(b, c) { - if (b) { - if ("string" == typeof b) return a(b, c); - var d = Object.prototype.toString.call(b).slice(8, -1); - if ("Object" === d && b.constructor && (d = b.constructor.name), "Map" === d || "Set" === d) return Array.from(d); - if ("Arguments" === d || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d)) return a(b, c); + })(a, c) || (function(a, c) { + if (a) { + if ("string" == typeof a) return b(a, c); + var d = Object.prototype.toString.call(a).slice(8, -1); + if ("Object" === d && a.constructor && (d = a.constructor.name), "Map" === d || "Set" === d) return Array.from(d); + if ("Arguments" === d || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d)) return b(a, c); } })(a, c) || (function() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); })(); -})(b, 1)[0]; +})(a, 1)[0]; var c = function() { "use strict"; !function(a, b) { diff --git a/packages/next-swc/crates/core/tests/loader/css-hygiene-1/output.js b/packages/next-swc/crates/core/tests/loader/css-hygiene-1/output.js index cd1517cec174d5a..ad93e37fb91f5b6 100644 --- a/packages/next-swc/crates/core/tests/loader/css-hygiene-1/output.js +++ b/packages/next-swc/crates/core/tests/loader/css-hygiene-1/output.js @@ -1,3 +1,3 @@ -var _defaultExport = new String("@media(max-width:870px){th.expiration-date-cell,td.expiration-date-cell{display:none}}"); +var _defaultExport = new String("@media (max-width:870px) {th.expiration-date-cell, td.expiration-date-cell{display:none}}"); _defaultExport.__hash = "fd71bf06ba8860bb"; export default _defaultExport; diff --git a/packages/next-swc/crates/core/tests/loader/example/output.js b/packages/next-swc/crates/core/tests/loader/example/output.js index 1bb38a8e44b6ec7..7bbcd606d5afaa2 100644 --- a/packages/next-swc/crates/core/tests/loader/example/output.js +++ b/packages/next-swc/crates/core/tests/loader/example/output.js @@ -1,3 +1,4 @@ +import other from 'other'; function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i]; @@ -49,7 +50,6 @@ function _unsupportedIterableToArray(o, minLen) { if (n === "Map" || n === "Set") return Array.from(n); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } -import other from 'other'; var _other = _slicedToArray(other, 1), foo = _other[0]; var Foo = function Foo() { "use strict"; diff --git a/packages/next-swc/crates/core/tests/loader/issue-31627/output.js b/packages/next-swc/crates/core/tests/loader/issue-31627/output.js index 1bd450ee9fafd47..abdbe09ac240763 100644 --- a/packages/next-swc/crates/core/tests/loader/issue-31627/output.js +++ b/packages/next-swc/crates/core/tests/loader/issue-31627/output.js @@ -1,10 +1,10 @@ +import { useEffect } from 'react'; +import { select, selectAll } from 'd3-selection'; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -import { useEffect } from 'react'; -import { select, selectAll } from 'd3-selection'; export default function Home() { useEffect(function() { new MyClass(); diff --git a/packages/next-swc/crates/core/tests/loader/styled-components/1/output.js b/packages/next-swc/crates/core/tests/loader/styled-components/1/output.js index 8e100ad666c08d1..70e1bb4afc6bb2a 100644 --- a/packages/next-swc/crates/core/tests/loader/styled-components/1/output.js +++ b/packages/next-swc/crates/core/tests/loader/styled-components/1/output.js @@ -1,3 +1,4 @@ +import styled from 'styled-components'; function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); @@ -17,7 +18,6 @@ function _templateObject() { }; return data; } -import styled from 'styled-components'; export var foo = styled.input.withConfig({ displayName: "input__foo", componentId: "sc-12c52e68-0" diff --git a/packages/next-swc/crates/napi/Cargo.toml b/packages/next-swc/crates/napi/Cargo.toml index 493424eb23bf58a..f7d20e9a64051cc 100644 --- a/packages/next-swc/crates/napi/Cargo.toml +++ b/packages/next-swc/crates/napi/Cargo.toml @@ -16,12 +16,12 @@ once_cell = "1.8.0" serde = "1" serde_json = "1" next-swc = { version = "0.0.0", path = "../core" } -swc = "0.126.2" +swc = "0.121.7" swc_atoms = "0.2.7" -swc_bundler = { version = "0.107.0", features = ["concurrent"] } +swc_bundler = { version = "0.105.0", features = ["concurrent"] } swc_common = { version = "0.17.0", features = ["concurrent", "sourcemap"] } swc_ecma_loader = { version = "0.28.0", features = ["node", "lru"] } -swc_ecmascript = { version = "0.114.2", features = ["codegen", "minifier", "optimization", "parser", "react", "transforms", "typescript", "utils", "visit"] } +swc_ecmascript = { version = "0.112.6", features = ["codegen", "minifier", "optimization", "parser", "react", "transforms", "typescript", "utils", "visit"] } swc_node_base = "0.5.1" [build-dependencies] diff --git a/packages/next-swc/crates/wasm/Cargo.toml b/packages/next-swc/crates/wasm/Cargo.toml index b25e21bcbe0e0cb..c84005528842b76 100644 --- a/packages/next-swc/crates/wasm/Cargo.toml +++ b/packages/next-swc/crates/wasm/Cargo.toml @@ -16,9 +16,9 @@ path-clean = "0.1" serde = {version = "1", features = ["derive"]} serde_json = "1" next-swc = { version = "0.0.0", path = "../core" } -swc = "0.126.2" +swc = "0.121.7" swc_common = { version = "0.17.0", features = ["concurrent", "sourcemap"] } -swc_ecmascript = { version = "0.114.2", features = ["codegen", "minifier", "optimization", "parser", "react", "transforms", "typescript", "utils", "visit"] } +swc_ecmascript = { version = "0.112.6", features = ["codegen", "minifier", "optimization", "parser", "react", "transforms", "typescript", "utils", "visit"] } tracing = {version = "0.1.28", features = ["release_max_level_off"]} wasm-bindgen = {version = "0.2", features = ["serde-serialize"]} wasm-bindgen-futures = "0.4.8" diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 98b823888fac326..833ddaa0263717a 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "private": true, "scripts": { "build-native": "napi build --platform --cargo-name next_swc_napi native", diff --git a/packages/next/client/dev/on-demand-entries-client.js b/packages/next/client/dev/on-demand-entries-client.js index 349f95f5c22de80..c68a9dd287e4e4b 100644 --- a/packages/next/client/dev/on-demand-entries-client.js +++ b/packages/next/client/dev/on-demand-entries-client.js @@ -11,7 +11,17 @@ export default async (page) => { } else { Router.ready(() => { setInterval(() => { - sendMessage(JSON.stringify({ event: 'ping', page: Router.pathname })) + // when notFound: true is returned we should use the notFoundPage + // as the Router.pathname will point to the 404 page but we want + // to ping the source page that returned notFound: true instead + const notFoundSrcPage = self.__NEXT_DATA__.notFoundSrcPage + const pathname = + (Router.pathname === '/404' || Router.pathname === '/_error') && + notFoundSrcPage + ? notFoundSrcPage + : Router.pathname + + sendMessage(JSON.stringify({ event: 'ping', page: pathname })) }, 2500) }) } diff --git a/packages/next/client/image.tsx b/packages/next/client/image.tsx index a634db7a22dd836..164e7595263508b 100644 --- a/packages/next/client/image.tsx +++ b/packages/next/client/image.tsx @@ -385,6 +385,10 @@ export default function Image({ isLazy = false } + if (src.endsWith('.svg') && !config.dangerouslyAllowSVG) { + unoptimized = true + } + if (process.env.NODE_ENV !== 'production') { if (!src) { throw new Error( diff --git a/packages/next/package.json b/packages/next/package.json index f36aff1563758cf..a1229df5bac032f 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -69,7 +69,7 @@ ] }, "dependencies": { - "@next/env": "12.0.11-canary.18", + "@next/env": "12.0.11-canary.19", "caniuse-lite": "^1.0.30001283", "postcss": "8.4.5", "styled-jsx": "5.0.0", @@ -117,11 +117,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "1.2.1", "@napi-rs/triples": "1.0.3", - "@next/polyfill-module": "12.0.11-canary.18", - "@next/polyfill-nomodule": "12.0.11-canary.18", - "@next/react-dev-overlay": "12.0.11-canary.18", - "@next/react-refresh-utils": "12.0.11-canary.18", - "@next/swc": "12.0.11-canary.18", + "@next/polyfill-module": "12.0.11-canary.19", + "@next/polyfill-nomodule": "12.0.11-canary.19", + "@next/react-dev-overlay": "12.0.11-canary.19", + "@next/react-refresh-utils": "12.0.11-canary.19", + "@next/swc": "12.0.11-canary.19", "@peculiar/webcrypto": "1.1.7", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index 6b4a6ace6885bf0..77160619770fe7e 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -1550,6 +1550,9 @@ export default abstract class Server { res.body('{"notFound":true}').send() return null } else { + if (this.renderOpts.dev) { + query.__nextNotFoundSrcPage = pathname + } await this.render404( req, res, diff --git a/packages/next/server/config.ts b/packages/next/server/config.ts index 5569927609806a6..f51deaa8254aaf0 100644 --- a/packages/next/server/config.ts +++ b/packages/next/server/config.ts @@ -351,6 +351,28 @@ function assignDefaults(userConfig: { [key: string]: any }) { ) } } + + if ( + typeof images.dangerouslyAllowSVG !== 'undefined' && + typeof images.dangerouslyAllowSVG !== 'boolean' + ) { + throw new Error( + `Specified images.dangerouslyAllowSVG should be a boolean + ', ' + )}), received (${images.dangerouslyAllowSVG}).\nSee more info here: https://nextjs.org/docs/messages/invalid-images-config` + ) + } + + if ( + typeof images.contentSecurityPolicy !== 'undefined' && + typeof images.contentSecurityPolicy !== 'string' + ) { + throw new Error( + `Specified images.contentSecurityPolicy should be a string + ', ' + )}), received (${images.contentSecurityPolicy}).\nSee more info here: https://nextjs.org/docs/messages/invalid-images-config` + ) + } } if (result.webpack5 === false) { diff --git a/packages/next/server/image-config.ts b/packages/next/server/image-config.ts index 41dd013b9f2dd2a..001745447c1aa8b 100644 --- a/packages/next/server/image-config.ts +++ b/packages/next/server/image-config.ts @@ -29,16 +29,22 @@ export type ImageConfigComplete = { path: string /** @see [Image domains configuration](https://nextjs.org/docs/basic-features/image-optimization#domains) */ - domains?: string[] + domains: string[] /** @see [Cache behavior](https://nextjs.org/docs/api-reference/next/image#caching-behavior) */ - disableStaticImages?: boolean + disableStaticImages: boolean /** @see [Cache behavior](https://nextjs.org/docs/api-reference/next/image#caching-behavior) */ - minimumCacheTTL?: number + minimumCacheTTL: number /** @see [Acceptable formats](https://nextjs.org/docs/api-reference/next/image#acceptable-formats) */ - formats?: ImageFormat[] + formats: ImageFormat[] + + /** @see [Dangerously Allow SVG](https://nextjs.org/docs/api-reference/next/image#dangerously-allow-svg) */ + dangerouslyAllowSVG: boolean + + /** @see [Dangerously Allow SVG](https://nextjs.org/docs/api-reference/next/image#dangerously-allow-svg) */ + contentSecurityPolicy: string } export type ImageConfig = Partial @@ -52,4 +58,6 @@ export const imageConfigDefault: ImageConfigComplete = { disableStaticImages: false, minimumCacheTTL: 60, formats: ['image/webp'], + dangerouslyAllowSVG: false, + contentSecurityPolicy: `script-src 'none'; frame-src 'none'; sandbox;`, } diff --git a/packages/next/server/image-optimizer.ts b/packages/next/server/image-optimizer.ts index 56feff6010b323f..35c10f24ed43eb5 100644 --- a/packages/next/server/image-optimizer.ts +++ b/packages/next/server/image-optimizer.ts @@ -380,6 +380,16 @@ export async function imageOptimizer( } } + if (upstreamType === SVG && !nextConfig.images.dangerouslyAllowSVG) { + console.error( + `The requested resource "${href}" has type "${upstreamType}" but dangerouslyAllowSVG is disabled` + ) + throw new ImageError( + 400, + '"url" parameter is valid but image type is not allowed' + ) + } + if (upstreamType) { const vector = VECTOR_TYPES.includes(upstreamType) const animate = @@ -576,14 +586,15 @@ function getFileNameWithExtension( return `${fileName}.${extension}` } -export function setResponseHeaders( +function setResponseHeaders( req: IncomingMessage, res: ServerResponse, url: string, etag: string, contentType: string | null, isStatic: boolean, - xCache: XCacheHeader + xCache: XCacheHeader, + contentSecurityPolicy: string ) { res.setHeader('Vary', 'Accept') res.setHeader( @@ -608,7 +619,9 @@ export function setResponseHeaders( ) } - res.setHeader('Content-Security-Policy', `script-src 'none'; sandbox;`) + if (contentSecurityPolicy) { + res.setHeader('Content-Security-Policy', contentSecurityPolicy) + } res.setHeader('X-Nextjs-Cache', xCache) return { finished: false } @@ -621,7 +634,8 @@ export function sendResponse( extension: string, buffer: Buffer, isStatic: boolean, - xCache: XCacheHeader + xCache: XCacheHeader, + contentSecurityPolicy: string ) { const contentType = getContentType(extension) const etag = getHash([buffer]) @@ -632,7 +646,8 @@ export function sendResponse( etag, contentType, isStatic, - xCache + xCache, + contentSecurityPolicy ) if (!result.finished) { res.end(buffer) diff --git a/packages/next/server/next-server.ts b/packages/next/server/next-server.ts index c259936ebc2ab75..4c7779481822445 100644 --- a/packages/next/server/next-server.ts +++ b/packages/next/server/next-server.ts @@ -255,7 +255,8 @@ export default class NextNodeServer extends BaseServer { cacheEntry.value.extension, cacheEntry.value.buffer, paramsResult.isStatic, - cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT' + cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT', + imagesConfig.contentSecurityPolicy ) } catch (err) { if (err instanceof ImageError) { diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx index e52b91eeabc264d..87b45ab0b44afb0 100644 --- a/packages/next/server/render.tsx +++ b/packages/next/server/render.tsx @@ -528,9 +528,11 @@ export async function renderToHTML( const headTags = (...args: any) => callMiddleware('headTags', args) const isFallback = !!query.__nextFallback + const notFoundSrcPage = query.__nextNotFoundSrcPage delete query.__nextFallback delete query.__nextLocale delete query.__nextDefaultLocale + delete query.__nextIsNotFound const isSSG = !!getStaticProps const isBuildTimeSSG = isSSG && renderOpts.nextExport @@ -1374,6 +1376,7 @@ export async function renderToHTML( defaultLocale, domainLocales, isPreview: isPreview === true ? true : undefined, + notFoundSrcPage: notFoundSrcPage && dev ? notFoundSrcPage : undefined, }, buildManifest: filteredBuildManifest, docComponentsRendered, diff --git a/packages/next/server/request-meta.ts b/packages/next/server/request-meta.ts index e2fed315088dc2c..f906e5f5f1f0559 100644 --- a/packages/next/server/request-meta.ts +++ b/packages/next/server/request-meta.ts @@ -53,6 +53,7 @@ export function addRequestMeta( } type NextQueryMetadata = { + __nextNotFoundSrcPage?: string __nextDefaultLocale?: string __nextFallback?: 'true' __nextLocale?: string diff --git a/packages/next/shared/lib/utils.ts b/packages/next/shared/lib/utils.ts index 6c22ce7ff852dc6..94196af4f597138 100644 --- a/packages/next/shared/lib/utils.ts +++ b/packages/next/shared/lib/utils.ts @@ -107,6 +107,7 @@ export type NEXT_DATA = { domainLocales?: DomainLocale[] scriptLoader?: any[] isPreview?: boolean + notFoundSrcPage?: string rsc?: boolean } diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index a81dcc722a6901a..df902443fcd62b8 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 12cb9722385323f..dbeed5ed378c5e7 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.0.11-canary.18", + "version": "12.0.11-canary.19", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/test/development/gssp-notfound/index.test.ts b/test/development/gssp-notfound/index.test.ts new file mode 100644 index 000000000000000..9ad292b9740514c --- /dev/null +++ b/test/development/gssp-notfound/index.test.ts @@ -0,0 +1,34 @@ +import { createNext } from 'e2e-utils' +import { NextInstance } from 'test/lib/next-modes/base' +import { waitFor } from 'next-test-utils' +import webdriver from 'next-webdriver' + +describe('getServerSideProps returns notFound: true', () => { + let next: NextInstance + + beforeAll(async () => { + next = await createNext({ + files: { + 'pages/index.js': ` + const Home = () => null + export default Home + + export function getServerSideProps() { + console.log("gssp called") + return { notFound: true } + } + `, + }, + dependencies: {}, + }) + }) + afterAll(() => next.destroy()) + + it('should not poll indefinitely', async () => { + const browser = await webdriver(next.appPort, '/') + await waitFor(3000) + await browser.close() + const logOccurrences = next.cliOutput.split('gssp called').length - 1 + expect(logOccurrences).toBe(1) + }) +}) diff --git a/test/integration/image-component/default/test/index.test.js b/test/integration/image-component/default/test/index.test.js index 8267389e1c948b2..0f390ed540d0222 100644 --- a/test/integration/image-component/default/test/index.test.js +++ b/test/integration/image-component/default/test/index.test.js @@ -208,7 +208,7 @@ function runTests(mode) { ) await check( () => browser.eval(`document.getElementById("img3").currentSrc`), - /test(.*)svg/ + /test\.svg/ ) await check( () => browser.eval(`document.getElementById("img4").currentSrc`), @@ -224,7 +224,7 @@ function runTests(mode) { ) await check( () => browser.eval(`document.getElementById("msg3").textContent`), - 'loaded 1 img3 with dimensions 266x266' + 'loaded 1 img3 with dimensions 400x400' ) await check( () => browser.eval(`document.getElementById("msg4").textContent`), @@ -1077,7 +1077,7 @@ function runTests(mode) { expect( await hasImageMatchingUrl( browser, - `http://localhost:${appPort}/_next/image?url=%2Ftest.svg&w=828&q=75` + `http://localhost:${appPort}/test.svg` ) ).toBe(true) expect( diff --git a/test/integration/image-optimizer/test/index.test.js b/test/integration/image-optimizer/test/index.test.js index 52797c7101667bd..44ae3d8b8b2b145 100644 --- a/test/integration/image-optimizer/test/index.test.js +++ b/test/integration/image-optimizer/test/index.test.js @@ -224,6 +224,56 @@ describe('Image Optimizer', () => { `Specified images.loader property (imgix) also requires images.path property to be assigned to a URL prefix.` ) }) + + it('should error when images.dangerouslyAllowSVG is not a boolean', async () => { + await nextConfig.replace( + '{ /* replaceme */ }', + JSON.stringify({ + images: { + dangerouslyAllowSVG: 'foo', + }, + }) + ) + let stderr = '' + + app = await launchApp(appDir, await findPort(), { + onStderr(msg) { + stderr += msg || '' + }, + }) + await waitFor(1000) + await killApp(app).catch(() => {}) + await nextConfig.restore() + + expect(stderr).toContain( + `Specified images.dangerouslyAllowSVG should be a boolean` + ) + }) + + it('should error when images.contentSecurityPolicy is not a string', async () => { + await nextConfig.replace( + '{ /* replaceme */ }', + JSON.stringify({ + images: { + contentSecurityPolicy: 1, + }, + }) + ) + let stderr = '' + + app = await launchApp(appDir, await findPort(), { + onStderr(msg) { + stderr += msg || '' + }, + }) + await waitFor(1000) + await killApp(app).catch(() => {}) + await nextConfig.restore() + + expect(stderr).toContain( + `Specified images.contentSecurityPolicy should be a string` + ) + }) }) // domains for testing @@ -240,11 +290,13 @@ describe('Image Optimizer', () => { describe('Server support for minimumCacheTTL in next.config.js', () => { const size = 96 // defaults defined in server/config.ts + const dangerouslyAllowSVG = true const ctx = { w: size, isDev: false, domains, minimumCacheTTL, + dangerouslyAllowSVG, imagesDir, appDir, } @@ -253,6 +305,7 @@ describe('Image Optimizer', () => { images: { domains, minimumCacheTTL, + dangerouslyAllowSVG, }, }) ctx.nextOutput = '' diff --git a/test/integration/image-optimizer/test/util.js b/test/integration/image-optimizer/test/util.js index 47867ab3b254d06..5c83a4fc74c5939 100644 --- a/test/integration/image-optimizer/test/util.js +++ b/test/integration/image-optimizer/test/util.js @@ -186,29 +186,39 @@ export function runTests(ctx) { expect(isAnimated(await res.buffer())).toBe(true) }) - it('should maintain vector svg', async () => { - const query = { w: ctx.w, q: 90, url: '/test.svg' } - const opts = { headers: { accept: 'image/webp' } } - const res = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts) - expect(res.status).toBe(200) - expect(res.headers.get('Content-Type')).toContain('image/svg+xml') - expect(res.headers.get('Cache-Control')).toBe( - `public, max-age=0, must-revalidate` - ) - // SVG is compressible so will have accept-encoding set from - // compression - expect(res.headers.get('Vary')).toMatch(/^Accept(,|$)/) - expect(res.headers.get('etag')).toBeTruthy() - expect(res.headers.get('Content-Disposition')).toBe( - `inline; filename="test.svg"` - ) - const actual = await res.text() - const expected = await fs.readFile( - join(ctx.appDir, 'public', 'test.svg'), - 'utf8' - ) - expect(actual).toMatch(expected) - }) + if (ctx.dangerouslyAllowSVG) { + it('should maintain vector svg', async () => { + const query = { w: ctx.w, q: 90, url: '/test.svg' } + const opts = { headers: { accept: 'image/webp' } } + const res = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts) + expect(res.status).toBe(200) + expect(res.headers.get('Content-Type')).toContain('image/svg+xml') + expect(res.headers.get('Cache-Control')).toBe( + `public, max-age=0, must-revalidate` + ) + // SVG is compressible so will have accept-encoding set from + // compression + expect(res.headers.get('Vary')).toMatch(/^Accept(,|$)/) + expect(res.headers.get('etag')).toBeTruthy() + expect(res.headers.get('Content-Disposition')).toBe( + `inline; filename="test.svg"` + ) + const actual = await res.text() + const expected = await fs.readFile( + join(ctx.appDir, 'public', 'test.svg'), + 'utf8' + ) + expect(actual).toMatch(expected) + }) + } else { + it('should not allow vector svg', async () => { + const query = { w: ctx.w, q: 35, url: '/test.svg' } + const opts = { headers: { accept: 'image/webp' } } + const res = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts) + expect(res.status).toBe(400) + expect(await res.text()).toContain('valid but image type is not allowed') + }) + } it('should maintain ico format', async () => { const query = { w: ctx.w, q: 90, url: `/test.ico` } @@ -778,41 +788,43 @@ export function runTests(ctx) { } }) - it('should use cached image file when parameters are the same for svg', async () => { - await cleanImagesDir(ctx) + if (ctx.dangerouslyAllowSVG) { + it('should use cached image file when parameters are the same for svg', async () => { + await cleanImagesDir(ctx) - const query = { url: '/test.svg', w: ctx.w, q: 80 } - const opts = { headers: { accept: 'image/webp' } } + const query = { url: '/test.svg', w: ctx.w, q: 80 } + const opts = { headers: { accept: 'image/webp' } } - const res1 = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts) - expect(res1.status).toBe(200) - expect(res1.headers.get('X-Nextjs-Cache')).toBe('MISS') - expect(res1.headers.get('Content-Type')).toBe('image/svg+xml') - expect(res1.headers.get('Content-Disposition')).toBe( - `inline; filename="test.svg"` - ) - const etagOne = res1.headers.get('etag') + const res1 = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts) + expect(res1.status).toBe(200) + expect(res1.headers.get('X-Nextjs-Cache')).toBe('MISS') + expect(res1.headers.get('Content-Type')).toBe('image/svg+xml') + expect(res1.headers.get('Content-Disposition')).toBe( + `inline; filename="test.svg"` + ) + const etagOne = res1.headers.get('etag') - let json1 - await check(async () => { - json1 = await fsToJson(ctx.imagesDir) - return Object.keys(json1).some((dir) => { - return Object.keys(json1[dir]).some((file) => file.includes(etagOne)) - }) - ? 'success' - : 'fail' - }, 'success') + let json1 + await check(async () => { + json1 = await fsToJson(ctx.imagesDir) + return Object.keys(json1).some((dir) => { + return Object.keys(json1[dir]).some((file) => file.includes(etagOne)) + }) + ? 'success' + : 'fail' + }, 'success') - const res2 = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts) - expect(res2.status).toBe(200) - expect(res2.headers.get('X-Nextjs-Cache')).toBe('HIT') - expect(res2.headers.get('Content-Type')).toBe('image/svg+xml') - expect(res2.headers.get('Content-Disposition')).toBe( - `inline; filename="test.svg"` - ) - const json2 = await fsToJson(ctx.imagesDir) - expect(json2).toStrictEqual(json1) - }) + const res2 = await fetchViaHTTP(ctx.appPort, '/_next/image', query, opts) + expect(res2.status).toBe(200) + expect(res2.headers.get('X-Nextjs-Cache')).toBe('HIT') + expect(res2.headers.get('Content-Type')).toBe('image/svg+xml') + expect(res2.headers.get('Content-Disposition')).toBe( + `inline; filename="test.svg"` + ) + const json2 = await fsToJson(ctx.imagesDir) + expect(json2).toStrictEqual(json1) + }) + } it('should use cached image file when parameters are the same for animated gif', async () => { await cleanImagesDir(ctx) diff --git a/test/integration/production/next.config.js b/test/integration/production/next.config.js index cc65ddf365179e0..e661257a8b2d0bf 100644 --- a/test/integration/production/next.config.js +++ b/test/integration/production/next.config.js @@ -39,4 +39,8 @@ module.exports = { }, ] }, + images: { + // Make sure we have sane default CSP, even when SVG is enabled + dangerouslyAllowSVG: true, + }, } diff --git a/test/integration/production/test/security.js b/test/integration/production/test/security.js index 6ce693ef84b7d0b..8a4778411b7a7dc 100644 --- a/test/integration/production/test/security.js +++ b/test/integration/production/test/security.js @@ -319,7 +319,7 @@ module.exports = (context) => { }) if (browserName !== 'internet explorer') { - it('should not execute script embedded inside svg image', async () => { + it('should not execute script embedded inside svg image, even if dangerouslyAllowSVG=true', async () => { let browser try { browser = await webdriver(context.appPort, '/svg-image')