diff --git a/packages/next/build/webpack/config/blocks/css/index.ts b/packages/next/build/webpack/config/blocks/css/index.ts index b807fe24926fe..bd99853ee2534 100644 --- a/packages/next/build/webpack/config/blocks/css/index.ts +++ b/packages/next/build/webpack/config/blocks/css/index.ts @@ -104,6 +104,7 @@ export const css = curry(async function css( options: { importLoaders: 1, sourceMap: true, + onlyLocals: ctx.isServer, modules: { // Disallow global style exports so we can code-split CSS and // not worry about loading order. diff --git a/test/integration/css/fixtures/single-module/pages/index.js b/test/integration/css/fixtures/single-module/pages/index.js new file mode 100644 index 0000000000000..79140b6b136c9 --- /dev/null +++ b/test/integration/css/fixtures/single-module/pages/index.js @@ -0,0 +1,11 @@ +import { redText } from './index.module.css' + +function Home() { + return ( +
+ This text should be red. +
+ ) +} + +export default Home diff --git a/test/integration/css/fixtures/single-module/pages/index.module.css b/test/integration/css/fixtures/single-module/pages/index.module.css new file mode 100644 index 0000000000000..08a38e09ef8ea --- /dev/null +++ b/test/integration/css/fixtures/single-module/pages/index.module.css @@ -0,0 +1,3 @@ +.redText { + color: red; +} diff --git a/test/integration/css/test/index.test.js b/test/integration/css/test/index.test.js index fe94594d59275..3a817c135d481 100644 --- a/test/integration/css/test/index.test.js +++ b/test/integration/css/test/index.test.js @@ -203,19 +203,19 @@ describe('CSS Support', () => { const { version, mappings, sourcesContent } = JSON.parse(cssMapContent) expect({ version, mappings, sourcesContent }).toMatchInlineSnapshot(` - Object { - "mappings": "AAAA,+CACE,4BACE,WACF,CAFA,mBACE,WACF,CAFA,uBACE,WACF,CAFA,wBACE,WACF,CAFA,cACE,WACF,CACF", - "sourcesContent": Array [ - "@media (480px <= width < 768px) { - ::placeholder { - color: green; - } - } - ", - ], - "version": 3, - } - `) + Object { + "mappings": "AAAA,+CACE,4BACE,WACF,CAFA,mBACE,WACF,CAFA,uBACE,WACF,CAFA,wBACE,WACF,CAFA,cACE,WACF,CACF", + "sourcesContent": Array [ + "@media (480px <= width < 768px) { + ::placeholder { + color: green; + } + } + ", + ], + "version": 3, + } + `) }) }) @@ -261,25 +261,25 @@ describe('CSS Support', () => { const { version, mappings, sourcesContent } = JSON.parse(cssMapContent) expect({ version, mappings, sourcesContent }).toMatchInlineSnapshot(` - Object { - "mappings": "AACA,gCACE,cACE,WACF,CACF,CAGA,OACE,eAA0B,CAA1B,gBACF", - "sourcesContent": Array [ - "/* this should pass through untransformed */ - @media (480px <= width < 768px) { - ::placeholder { - color: green; - } - } - - /* this should be transformed to width/height */ - .video { - -xyz-max-size: 400px 300px; - } - ", - ], - "version": 3, - } - `) + Object { + "mappings": "AACA,gCACE,cACE,WACF,CACF,CAGA,OACE,eAA0B,CAA1B,gBACF", + "sourcesContent": Array [ + "/* this should pass through untransformed */ + @media (480px <= width < 768px) { + ::placeholder { + color: green; + } + } + + /* this should be transformed to width/height */ + .video { + -xyz-max-size: 400px 300px; + } + ", + ], + "version": 3, + } + `) }) }) @@ -674,12 +674,12 @@ describe('CSS Support', () => { ) .sort() ).toMatchInlineSnapshot(` - Array [ - "dark.svg", - "dark2.svg", - "light.svg", - ] - `) + Array [ + "dark.svg", + "dark2.svg", + "light.svg", + ] + `) }) }) @@ -800,4 +800,60 @@ describe('CSS Support', () => { expect(cssMapFiles.length).toBe(1) }) }) + + describe('Basic CSS Module Support', () => { + const appDir = join(fixturesDir, 'single-module') + + beforeAll(async () => { + await remove(join(appDir, '.next')) + }) + + let appPort + let app + beforeAll(async () => { + await nextBuild(appDir) + const server = nextServer({ + dir: appDir, + dev: false, + quiet: true, + }) + + app = await startApp(server) + appPort = app.address().port + }) + afterAll(async () => { + await stopApp(app) + }) + + it(`should've emitted a single CSS file`, async () => { + const cssFolder = join(appDir, '.next/static/css') + + const files = await readdir(cssFolder) + const cssFiles = files.filter(f => /\.css$/.test(f)) + + expect(cssFiles.length).toBe(1) + const cssContent = await readFile(join(cssFolder, cssFiles[0]), 'utf8') + + expect( + cssContent.replace(/\/\*.*?\*\//g, '').trim() + ).toMatchInlineSnapshot(`".index_redText__3CwEB{color:red}"`) + }) + + it(`should've injected the CSS on server render`, async () => { + const content = await renderViaHTTP(appPort, '/') + const $ = cheerio.load(content) + + const cssPreload = $('link[rel="preload"][as="style"]') + expect(cssPreload.length).toBe(1) + expect(cssPreload.attr('href')).toMatch(/^\/_next\/static\/css\/.*\.css$/) + + const cssSheet = $('link[rel="stylesheet"]') + expect(cssSheet.length).toBe(1) + expect(cssSheet.attr('href')).toMatch(/^\/_next\/static\/css\/.*\.css$/) + + expect($('#verify-red').attr('class')).toMatchInlineSnapshot( + `"index_redText__3CwEB"` + ) + }) + }) })