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')