From e2b64dd9d95f77a22f00e51aa39e1dbddaa297d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Sun, 23 Oct 2022 11:38:08 +0200 Subject: [PATCH 1/7] add tests --- .../app/app/css/sass-client/global.sass | 3 + .../app/app/css/sass-client/global.scss | 3 + .../app/app/css/sass-client/inner/global.sass | 3 + .../app/app/css/sass-client/inner/global.scss | 3 + .../app/app/css/sass-client/inner/page.js | 19 +++ .../css/sass-client/inner/styles.module.sass | 2 + .../css/sass-client/inner/styles.module.scss | 3 + .../app-dir/app/app/css/sass-client/layout.js | 20 +++ .../app/css/sass-client/styles.module.sass | 2 + .../app/css/sass-client/styles.module.scss | 3 + test/e2e/app-dir/app/app/css/sass/global.sass | 3 + test/e2e/app-dir/app/app/css/sass/global.scss | 3 + .../app/app/css/sass/inner/global.sass | 3 + .../app/app/css/sass/inner/global.scss | 3 + .../app-dir/app/app/css/sass/inner/page.js | 17 +++ .../app/app/css/sass/inner/styles.module.sass | 2 + .../app/app/css/sass/inner/styles.module.scss | 3 + test/e2e/app-dir/app/app/css/sass/layout.js | 18 +++ .../app/app/css/sass/styles.module.sass | 2 + .../app/app/css/sass/styles.module.scss | 3 + test/e2e/app-dir/index.test.ts | 138 ++++++++++++++++++ 21 files changed, 256 insertions(+) create mode 100644 test/e2e/app-dir/app/app/css/sass-client/global.sass create mode 100644 test/e2e/app-dir/app/app/css/sass-client/global.scss create mode 100644 test/e2e/app-dir/app/app/css/sass-client/inner/global.sass create mode 100644 test/e2e/app-dir/app/app/css/sass-client/inner/global.scss create mode 100644 test/e2e/app-dir/app/app/css/sass-client/inner/page.js create mode 100644 test/e2e/app-dir/app/app/css/sass-client/inner/styles.module.sass create mode 100644 test/e2e/app-dir/app/app/css/sass-client/inner/styles.module.scss create mode 100644 test/e2e/app-dir/app/app/css/sass-client/layout.js create mode 100644 test/e2e/app-dir/app/app/css/sass-client/styles.module.sass create mode 100644 test/e2e/app-dir/app/app/css/sass-client/styles.module.scss create mode 100644 test/e2e/app-dir/app/app/css/sass/global.sass create mode 100644 test/e2e/app-dir/app/app/css/sass/global.scss create mode 100644 test/e2e/app-dir/app/app/css/sass/inner/global.sass create mode 100644 test/e2e/app-dir/app/app/css/sass/inner/global.scss create mode 100644 test/e2e/app-dir/app/app/css/sass/inner/page.js create mode 100644 test/e2e/app-dir/app/app/css/sass/inner/styles.module.sass create mode 100644 test/e2e/app-dir/app/app/css/sass/inner/styles.module.scss create mode 100644 test/e2e/app-dir/app/app/css/sass/layout.js create mode 100644 test/e2e/app-dir/app/app/css/sass/styles.module.sass create mode 100644 test/e2e/app-dir/app/app/css/sass/styles.module.scss diff --git a/test/e2e/app-dir/app/app/css/sass-client/global.sass b/test/e2e/app-dir/app/app/css/sass-client/global.sass new file mode 100644 index 0000000000000..febf593dd789c --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass-client/global.sass @@ -0,0 +1,3 @@ +#sass-client-layout + color: brown + diff --git a/test/e2e/app-dir/app/app/css/sass-client/global.scss b/test/e2e/app-dir/app/app/css/sass-client/global.scss new file mode 100644 index 0000000000000..d9a5d9d523b9d --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass-client/global.scss @@ -0,0 +1,3 @@ +#scss-client-layout { + color: burlywood; +} diff --git a/test/e2e/app-dir/app/app/css/sass-client/inner/global.sass b/test/e2e/app-dir/app/app/css/sass-client/inner/global.sass new file mode 100644 index 0000000000000..6cf30f33ff606 --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass-client/inner/global.sass @@ -0,0 +1,3 @@ +#sass-client-page + color: wheat + diff --git a/test/e2e/app-dir/app/app/css/sass-client/inner/global.scss b/test/e2e/app-dir/app/app/css/sass-client/inner/global.scss new file mode 100644 index 0000000000000..05c93b6448efd --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass-client/inner/global.scss @@ -0,0 +1,3 @@ +#scss-client-page { + color: tomato; +} diff --git a/test/e2e/app-dir/app/app/css/sass-client/inner/page.js b/test/e2e/app-dir/app/app/css/sass-client/inner/page.js new file mode 100644 index 0000000000000..ad208ca88190d --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass-client/inner/page.js @@ -0,0 +1,19 @@ +'use client' + +import './global.scss' +import './global.sass' +import sass from './styles.module.sass' +import scss from './styles.module.scss' + +export default function Page() { + return ( + <> +
+ sass client page +
+
+ scss client page +
+ + ) +} diff --git a/test/e2e/app-dir/app/app/css/sass-client/inner/styles.module.sass b/test/e2e/app-dir/app/app/css/sass-client/inner/styles.module.sass new file mode 100644 index 0000000000000..e1f5b5d0e487f --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass-client/inner/styles.module.sass @@ -0,0 +1,2 @@ +.mod + background-color: indigo diff --git a/test/e2e/app-dir/app/app/css/sass-client/inner/styles.module.scss b/test/e2e/app-dir/app/app/css/sass-client/inner/styles.module.scss new file mode 100644 index 0000000000000..e84d60fe479cf --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass-client/inner/styles.module.scss @@ -0,0 +1,3 @@ +.mod { + background-color: aqua; +} diff --git a/test/e2e/app-dir/app/app/css/sass-client/layout.js b/test/e2e/app-dir/app/app/css/sass-client/layout.js new file mode 100644 index 0000000000000..fa6713af90e2f --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass-client/layout.js @@ -0,0 +1,20 @@ +'use client' + +import './global.scss' +import './global.sass' +import sass from './styles.module.sass' +import scss from './styles.module.scss' + +export default function Layout({ children }) { + return ( + <> +
+ sass client layout +
+
+ scss client layout +
+ {children} + + ) +} diff --git a/test/e2e/app-dir/app/app/css/sass-client/styles.module.sass b/test/e2e/app-dir/app/app/css/sass-client/styles.module.sass new file mode 100644 index 0000000000000..725bb78d164a4 --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass-client/styles.module.sass @@ -0,0 +1,2 @@ +.mod + background-color: darksalmon diff --git a/test/e2e/app-dir/app/app/css/sass-client/styles.module.scss b/test/e2e/app-dir/app/app/css/sass-client/styles.module.scss new file mode 100644 index 0000000000000..185167dd39fd2 --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass-client/styles.module.scss @@ -0,0 +1,3 @@ +.mod { + background-color: darkred; +} diff --git a/test/e2e/app-dir/app/app/css/sass/global.sass b/test/e2e/app-dir/app/app/css/sass/global.sass new file mode 100644 index 0000000000000..f692b6266a6d9 --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass/global.sass @@ -0,0 +1,3 @@ +#sass-server-layout + color: brown + diff --git a/test/e2e/app-dir/app/app/css/sass/global.scss b/test/e2e/app-dir/app/app/css/sass/global.scss new file mode 100644 index 0000000000000..1f8677ff440e5 --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass/global.scss @@ -0,0 +1,3 @@ +#scss-server-layout { + color: burlywood; +} diff --git a/test/e2e/app-dir/app/app/css/sass/inner/global.sass b/test/e2e/app-dir/app/app/css/sass/inner/global.sass new file mode 100644 index 0000000000000..509da5744d11c --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass/inner/global.sass @@ -0,0 +1,3 @@ +#sass-server-page + color: wheat + diff --git a/test/e2e/app-dir/app/app/css/sass/inner/global.scss b/test/e2e/app-dir/app/app/css/sass/inner/global.scss new file mode 100644 index 0000000000000..8cce88945a2c1 --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass/inner/global.scss @@ -0,0 +1,3 @@ +#scss-server-page { + color: tomato; +} diff --git a/test/e2e/app-dir/app/app/css/sass/inner/page.js b/test/e2e/app-dir/app/app/css/sass/inner/page.js new file mode 100644 index 0000000000000..fdb01e5056c86 --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass/inner/page.js @@ -0,0 +1,17 @@ +import './global.scss' +import './global.sass' +import sass from './styles.module.sass' +import scss from './styles.module.scss' + +export default function Page() { + return ( + <> +
+ sass server page +
+
+ scss server page +
+ + ) +} diff --git a/test/e2e/app-dir/app/app/css/sass/inner/styles.module.sass b/test/e2e/app-dir/app/app/css/sass/inner/styles.module.sass new file mode 100644 index 0000000000000..e1f5b5d0e487f --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass/inner/styles.module.sass @@ -0,0 +1,2 @@ +.mod + background-color: indigo diff --git a/test/e2e/app-dir/app/app/css/sass/inner/styles.module.scss b/test/e2e/app-dir/app/app/css/sass/inner/styles.module.scss new file mode 100644 index 0000000000000..e84d60fe479cf --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass/inner/styles.module.scss @@ -0,0 +1,3 @@ +.mod { + background-color: aqua; +} diff --git a/test/e2e/app-dir/app/app/css/sass/layout.js b/test/e2e/app-dir/app/app/css/sass/layout.js new file mode 100644 index 0000000000000..a0b928bdf9d86 --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass/layout.js @@ -0,0 +1,18 @@ +import './global.scss' +import './global.sass' +import sass from './styles.module.sass' +import scss from './styles.module.scss' + +export default function Layout({ children }) { + return ( + <> +
+ sass server layout +
+
+ scss server layout +
+ {children} + + ) +} diff --git a/test/e2e/app-dir/app/app/css/sass/styles.module.sass b/test/e2e/app-dir/app/app/css/sass/styles.module.sass new file mode 100644 index 0000000000000..725bb78d164a4 --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass/styles.module.sass @@ -0,0 +1,2 @@ +.mod + background-color: darksalmon diff --git a/test/e2e/app-dir/app/app/css/sass/styles.module.scss b/test/e2e/app-dir/app/app/css/sass/styles.module.scss new file mode 100644 index 0000000000000..185167dd39fd2 --- /dev/null +++ b/test/e2e/app-dir/app/app/css/sass/styles.module.scss @@ -0,0 +1,3 @@ +.mod { + background-color: darkred; +} diff --git a/test/e2e/app-dir/index.test.ts b/test/e2e/app-dir/index.test.ts index 13380335692b8..8fc1adfbe34b1 100644 --- a/test/e2e/app-dir/index.test.ts +++ b/test/e2e/app-dir/index.test.ts @@ -1374,6 +1374,144 @@ describe('app dir', () => { }) }) }) + describe('sass support', () => { + describe('server layouts', () => { + it('should support global sass/scss inside server layouts', async () => { + const browser = await webdriver(next.url, '/css/sass/inner') + // .sass + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#sass-server-layout')).color` + ) + ).toBe('rgb(165, 42, 42)') + // .scss + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#scss-server-layout')).color` + ) + ).toBe('rgb(222, 184, 135)') + }) + + it('should support sass/scss modules inside server layouts', async () => { + const browser = await webdriver(next.url, '/css/sass/inner') + // .sass + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#sass-server-layout')).backgroundColor` + ) + ).toBe('rgb(233, 150, 122)') + // .scss + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#scss-server-layout')).backgroundColor` + ) + ).toBe('rgb(139, 0, 0)') + }) + }) + + describe('server pages', () => { + it('should support global sass/scss inside server pages', async () => { + const browser = await webdriver(next.url, '/css/sass/inner') + // .sass + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#sass-server-page')).color` + ) + ).toBe('rgb(245, 222, 179)') + // .scss + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#scss-server-page')).color` + ) + ).toBe('rgb(255, 99, 71)') + }) + + it('should support sass/scss modules inside server pages', async () => { + const browser = await webdriver(next.url, '/css/sass/inner') + // .sass + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#sass-server-page')).backgroundColor` + ) + ).toBe('rgb(75, 0, 130)') + // .scss + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#scss-server-page')).backgroundColor` + ) + ).toBe('rgb(0, 255, 255)') + }) + }) + + describe('client layouts', () => { + it('should support global sass/scss inside client layouts', async () => { + const browser = await webdriver(next.url, '/css/sass/inner') + // .sass + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#sass-client-layout')).color` + ) + ).toBe('rgb(165, 42, 42)') + // .scss + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#scss-client-layout')).color` + ) + ).toBe('rgb(222, 184, 135)') + }) + + it('should support sass/scss modules inside client layouts', async () => { + const browser = await webdriver(next.url, '/css/sass/inner') + // .sass + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#sass-client-layout')).backgroundColor` + ) + ).toBe('rgb(233, 150, 122)') + // .scss + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#scss-client-layout')).backgroundColor` + ) + ).toBe('rgb(139, 0, 0)') + }) + }) + }) + + describe('client pages', () => { + it('should support global sass/scss inside client pages', async () => { + const browser = await webdriver(next.url, '/css/sass-client/inner') + await waitFor(5000) + // .sass + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#sass-client-page')).color` + ) + ).toBe('rgb(245, 222, 179)') + // .scss + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#scss-client-page')).color` + ) + ).toBe('rgb(255, 99, 71)') + }) + + it('should support sass/scss modules inside client pages', async () => { + const browser = await webdriver(next.url, '/css/sass-client/inner') + // .sass + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#sass-client-page')).backgroundColor` + ) + ).toBe('rgb(75, 0, 130)') + // .scss + expect( + await browser.eval( + `window.getComputedStyle(document.querySelector('#scss-client-page')).backgroundColor` + ) + ).toBe('rgb(0, 255, 255)') + }) + }) ;(isDev ? describe.skip : describe)('Subresource Integrity', () => { function fetchWithPolicy(policy: string | null) { return fetchViaHTTP(next.url, '/dashboard', undefined, { From a52699cc31c910322a487c776bced7ea94e9438a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Sun, 23 Oct 2022 11:39:48 +0200 Subject: [PATCH 2/7] include sass & scss in regex --- packages/next/build/webpack/loaders/utils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/next/build/webpack/loaders/utils.ts b/packages/next/build/webpack/loaders/utils.ts index dbaf39b0508ac..d098ba9681a09 100644 --- a/packages/next/build/webpack/loaders/utils.ts +++ b/packages/next/build/webpack/loaders/utils.ts @@ -11,5 +11,4 @@ export function isClientComponentModule(mod: { return hasClientDirective || imageRegex.test(mod.resource) } -// TODO-APP: ensure .scss / .sass also works. -export const regexCSS = /\.css(\?.*)?$/ +export const regexCSS = /\.(css|scss|sass)(\?.*)?$/ From fa65ccc59bf626d4cd3346c8f8c53210a4c5fdb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Sun, 23 Oct 2022 13:15:29 +0200 Subject: [PATCH 3/7] Add loaders for sass --- .../build/webpack/config/blocks/css/index.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/packages/next/build/webpack/config/blocks/css/index.ts b/packages/next/build/webpack/config/blocks/css/index.ts index 5ebfbf8e62aac..38154cb787e9e 100644 --- a/packages/next/build/webpack/config/blocks/css/index.ts +++ b/packages/next/build/webpack/config/blocks/css/index.ts @@ -456,6 +456,28 @@ export const css = curry(async function css( ], }) ) + fns.push( + loader({ + oneOf: [ + markRemovable({ + // A global SASS import always has side effects. Webpack will tree + // shake the CSS without this option if the issuer claims to have + // no side-effects. + // See https://github.com/webpack/webpack/issues/6571 + sideEffects: true, + test: regexSassGlobal, + use: [ + require.resolve('../../../loaders/next-flight-css-dev-loader'), + ...getGlobalCssLoader( + ctx, + lazyPostCSSInitializer, + sassPreprocessors + ), + ], + }), + ], + }) + ) fns.push( loader({ oneOf: [ @@ -470,6 +492,24 @@ export const css = curry(async function css( ], }) ) + fns.push( + loader({ + oneOf: [ + markRemovable({ + sideEffects: false, + test: regexSassModules, + use: [ + require.resolve('../../../loaders/next-flight-css-dev-loader'), + ...getCssModuleLoader( + ctx, + lazyPostCSSInitializer, + sassPreprocessors + ), + ], + }), + ], + }) + ) } else { fns.push( loader({ From cbf97170872e8569c6e099d4ea7b59ded72d8569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Sun, 23 Oct 2022 13:15:57 +0200 Subject: [PATCH 4/7] Add sass to flights css dev loader --- .../next/build/webpack/loaders/next-flight-css-dev-loader.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next/build/webpack/loaders/next-flight-css-dev-loader.ts b/packages/next/build/webpack/loaders/next-flight-css-dev-loader.ts index 30947cd00dd62..8bfd62b9f38f1 100644 --- a/packages/next/build/webpack/loaders/next-flight-css-dev-loader.ts +++ b/packages/next/build/webpack/loaders/next-flight-css-dev-loader.ts @@ -5,7 +5,7 @@ */ export function pitch(this: any) { - const content = this.fs.readFileSync(this.resource) + const content = this.fs.readFileSync(this.resourcePath) this.data.__checksum = ( typeof content === 'string' ? Buffer.from(content) : content ).toString('hex') @@ -14,7 +14,7 @@ export function pitch(this: any) { const NextServerCSSLoader = function (this: any, content: string) { this.cacheable && this.cacheable() - const isCSSModule = this.resource.match(/\.module\.css$/) + const isCSSModule = this.resourcePath.match(/\.module\.(css|sass|scss)$/) if (isCSSModule) { return ( content + From c0f68bdd9c4d5776f9b331b033a467f5b3b385d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Sun, 23 Oct 2022 13:16:42 +0200 Subject: [PATCH 5/7] .css -> regex --- .../build/webpack/loaders/next-flight-client-entry-loader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/build/webpack/loaders/next-flight-client-entry-loader.ts b/packages/next/build/webpack/loaders/next-flight-client-entry-loader.ts index b35b000bdffac..ac8cd9b7c23f8 100644 --- a/packages/next/build/webpack/loaders/next-flight-client-entry-loader.ts +++ b/packages/next/build/webpack/loaders/next-flight-client-entry-loader.ts @@ -25,7 +25,7 @@ export default async function transformSource(this: any): Promise { // Filter out css files on the server .filter((request) => (isServer ? !regexCSS.test(request) : true)) .map((request) => - request.endsWith('.css') + regexCSS.test(request) ? `(() => import(/* webpackMode: "lazy" */ ${JSON.stringify(request)}))` : `import(/* webpackMode: "eager" */ ${JSON.stringify(request)})` ) From 9249fe5b38edc206115f00642db1c5189d21e874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Sun, 23 Oct 2022 16:59:38 -0700 Subject: [PATCH 6/7] fix tests --- test/e2e/app-dir/index.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/e2e/app-dir/index.test.ts b/test/e2e/app-dir/index.test.ts index 8fc1adfbe34b1..6ab9690183bbb 100644 --- a/test/e2e/app-dir/index.test.ts +++ b/test/e2e/app-dir/index.test.ts @@ -30,6 +30,7 @@ describe('app dir', () => { dependencies: { react: 'experimental', 'react-dom': 'experimental', + sass: 'latest', }, skipStart: true, }) @@ -1445,7 +1446,7 @@ describe('app dir', () => { describe('client layouts', () => { it('should support global sass/scss inside client layouts', async () => { - const browser = await webdriver(next.url, '/css/sass/inner') + const browser = await webdriver(next.url, '/css/sass-client/inner') // .sass expect( await browser.eval( @@ -1461,7 +1462,7 @@ describe('app dir', () => { }) it('should support sass/scss modules inside client layouts', async () => { - const browser = await webdriver(next.url, '/css/sass/inner') + const browser = await webdriver(next.url, '/css/sass-client/inner') // .sass expect( await browser.eval( From dd9091e9251c514f47a2e6f59f353180a9d2b6be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Sun, 23 Oct 2022 18:20:20 -0700 Subject: [PATCH 7/7] Add missing dep --- test/e2e/app-dir/vercel-analytics.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/e2e/app-dir/vercel-analytics.test.ts b/test/e2e/app-dir/vercel-analytics.test.ts index f6862ac4aa33d..08b6b1252e47c 100644 --- a/test/e2e/app-dir/vercel-analytics.test.ts +++ b/test/e2e/app-dir/vercel-analytics.test.ts @@ -21,6 +21,7 @@ describe('vercel analytics', () => { dependencies: { react: 'experimental', 'react-dom': 'experimental', + sass: 'latest', }, skipStart: true, env: {