diff --git a/docs/basic-features/built-in-css-support.md b/docs/basic-features/built-in-css-support.md index 1b26fbd45b62..1bc6a1274659 100644 --- a/docs/basic-features/built-in-css-support.md +++ b/docs/basic-features/built-in-css-support.md @@ -1,17 +1,126 @@ --- -description: Next.js includes styled-jsx by default for isolated and scoped CSS support, but you can also use any other CSS-in-JS solution!. Learn more here. +description: Next.js supports including CSS files as Global CSS or CSS Modules, using `styled-jsx` for CSS-in-JS, or any other CSS-in-JS solution! Learn more here. --- -# Built-in CSS Support +# Built-In CSS Support + +Next.js allows you to import CSS files from a JavaScript file. +This is possible because Next.js extends the concept of [`import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) beyond JavaScript. + +## Adding a Global Stylesheet + +To add a stylesheet to your application, import the CSS file within `pages/_app.js`. + +For example, consider the following stylesheet named `styles.css`: + +```css +body { + font-family: 'SF Pro Text', 'SF Pro Icons', system-ui; + padding: 20px 20px 60px; + max-width: 680px; + margin: 0 auto; +} +``` + +Create a [`pages/_app.js` file](https://nextjs.org/docs/advanced-features/custom-app) if not already present. +Then, [`import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) the `styles.css` file. + +```jsx +import '../styles.css' + +// This default export is required in a new `pages/_app.js` file. +export default function MyApp({ Component, pageProps }) { + return +} +``` + +These styles (`styles.css`) will apply to all pages and components in your application. +Due to the global nature of stylesheets, and to avoid conflicts, you may **only import them inside [`pages/_app.js`](https://nextjs.org/docs/advanced-features/custom-app)**. + +In development, expressing stylesheets this way allows your styles to be hot reloaded as you edit them—meaning you can keep application state. + +In production, all CSS files will be automatically concatenated into a single minified `.css` file. + +## Adding Component-Level CSS + +Next.js supports [CSS Modules](https://github.com/css-modules/css-modules) using the `[name].module.css` file naming convention. + +CSS Modules locally scope CSS by automatically creating a unique class name. +This allows you to use the same CSS class name in different files without worrying about collisions. + +This behavior makes CSS Modules the ideal way to include component-level CSS. +CSS Module files **can be imported anywhere in your application**. + +For example, consider a reusable `Button` component in the `components/` folder: + +First, create `components/Button.module.css` with the following content: + +```css +/* +You do not need to worry about .error {} colliding with any other `.css` or +`.module.css` files! +*/ +.error { + color: white; + background-color: red; +} +``` + +Then, create `components/Button.js`, importing and using the above CSS file: + +```jsx +import styles from './Button.module.css' + +export function Button() { + return ( + + ) +} +``` + +CSS Modules are an _optional feature_ and are **only enabled for files with the `.module.css` extension**. +Regular `` stylesheets and global CSS files are still supported. + +In production, all CSS Module files will be automatically concatenated into **many minified and code-split** `.css` files. +These `.css` files represent hot execution paths in your application, ensuring the minimal amount of CSS is loaded for your application to paint. + +## CSS-in-JS
Examples
-We bundle [styled-jsx](https://github.com/zeit/styled-jsx) to provide support for isolated scoped CSS. The aim is to support "shadow CSS" similar to Web Components, which unfortunately [do not support server-rendering and are JS-only](https://github.com/w3c/webcomponents/issues/71). +It's possible to use any existing CSS-in-JS solution. +The simplest one is inline styles: + +```jsx +function HiThere() { + return

hi there

+} + +export default HiThere +``` + +We bundle [styled-jsx](https://github.com/zeit/styled-jsx) to provide support for isolated scoped CSS. +The aim is to support "shadow CSS" similar to Web Components, which unfortunately [do not support server-rendering and are JS-only](https://github.com/w3c/webcomponents/issues/71). + +See the above examples for other popular CSS-in-JS solutions (like Styled Components). A component using `styled-jsx` looks like this: @@ -48,35 +157,10 @@ export default HelloWorld Please see the [styled-jsx documentation](https://github.com/zeit/styled-jsx) for more examples. -## CSS-in-JS - -
- Examples - -
- -It's possible to use any existing CSS-in-JS solution. The simplest one is inline styles: - -```jsx -function HiThere() { - return

hi there

-} - -export default HiThere -``` - -## CSS Plugins +## Sass, Less, and Stylus Support -To support importing `.css`, `.scss`, `.less` or `.styl` files you can use the following modules, which configure sensible defaults for server rendered applications: +To support importing `.scss`, `.less` or `.styl` files you can use the following plugins: -- [@zeit/next-css](https://github.com/zeit/next-plugins/tree/master/packages/next-css) - [@zeit/next-sass](https://github.com/zeit/next-plugins/tree/master/packages/next-sass) - [@zeit/next-less](https://github.com/zeit/next-plugins/tree/master/packages/next-less) - [@zeit/next-stylus](https://github.com/zeit/next-plugins/tree/master/packages/next-stylus) diff --git a/docs/deployment.md b/docs/deployment.md index 00ceb6c3703f..17e82c01f762 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -60,11 +60,11 @@ HTTPS is enabled by default and doesn't require extra configuration. #### From a git repository -You can link your project in [GitHub](https://zeit.co/new), [GitLab](https://zeit.co/new), or [Bitbucket](https://zeit.co/new) through the [web interface](https://zeit.co/new). This will automatically set up deployment previews for pull requests and commits. +You can link your project in [GitHub](https://zeit.co/new), [GitLab](https://zeit.co/new), or [Bitbucket](https://zeit.co/new) through the [web interface](https://zeit.co/new). This will automatically set up deployment previews for pull requests and commits. To learn more about ZEIT Now’s Git integration, take a look at [our documentation here](https://zeit.co/docs/v2/git-integration/). #### Through the ZEIT Now CLI -You can install the command line tool using npm: +You can install [Now CLI](https://zeit.co/download) from either npm or Yarn. Using npm, run the following command from your terminal: ```bash npm install -g now @@ -78,6 +78,10 @@ now You will receive a unique link similar to the following: https://your-project.username.now.sh. +#### Custom domains + +Once deployed on ZEIT Now, your projects can be assigned to a custom domain of your choice. To learn more, take a look at [our documentation here](https://zeit.co/docs/v2/custom-domains/). + ## Self hosting Next.js can be deployed to any hosting provider that supports Node.js. In order to self-host there are two commands: `next build` and `next start`. diff --git a/examples/basic-export/README.md b/examples/basic-export/README.md index 131a7768072f..747032cafc6c 100644 --- a/examples/basic-export/README.md +++ b/examples/basic-export/README.md @@ -40,8 +40,6 @@ yarn dev Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download)): ```bash -npm run export -cd out now ``` diff --git a/examples/basic-export/package.json b/examples/basic-export/package.json index 742fca1b5806..031909300b13 100644 --- a/examples/basic-export/package.json +++ b/examples/basic-export/package.json @@ -3,9 +3,8 @@ "version": "1.0.0", "scripts": { "dev": "next", - "build": "next build", - "start": "next start", - "export": "next export" + "build": "next build && next export", + "start": "next start" }, "dependencies": { "next": "latest", diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 528715fdd5a2..b78604b92abe 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -432,8 +432,7 @@ export default async function getBaseWebpackConfig( // are relative to requests we've already resolved here. // Absolute requires (require('/foo')) are extremely uncommon, but // also have no need for customization as they're already resolved. - const start = request.charAt(0) - if (start === '.' || start === '/') { + if (request.startsWith('.') || request.startsWith('/')) { return callback() } diff --git a/packages/next/build/webpack/plugins/next-esm-plugin.ts b/packages/next/build/webpack/plugins/next-esm-plugin.ts index ff323ac75c47..91a6f21b4abf 100644 --- a/packages/next/build/webpack/plugins/next-esm-plugin.ts +++ b/packages/next/build/webpack/plugins/next-esm-plugin.ts @@ -213,22 +213,30 @@ export default class NextEsmPlugin implements Plugin { compilation.namedChunkGroups ) + const unnamedChunks: compilation.Chunk[] = [] const childChunkFileMap = childCompilation.chunks.reduce( ( chunkMap: { [key: string]: compilation.Chunk }, chunk: compilation.Chunk ) => { - chunkMap[chunk.name] = chunk + // Dynamic chunks may not have a name. It'll be null in such cases + if (chunk.name === null) { + unnamedChunks.push(chunk) + } else { + chunkMap[chunk.name] = chunk + } + return chunkMap }, {} ) - // Merge files from similar chunks + // Merge chunks - merge the files of chunks with the same name compilation.chunks.forEach((chunk: compilation.Chunk) => { const childChunk = childChunkFileMap[chunk.name] - if (childChunk?.files) { + // Do not merge null named chunks since they are different + if (chunk.name !== null && childChunk?.files) { delete childChunkFileMap[chunk.name] chunk.files.push( ...childChunk.files.filter((v: any) => !chunk.files.includes(v)) @@ -236,15 +244,22 @@ export default class NextEsmPlugin implements Plugin { } }) - // Add modern only chunks - compilation.chunks.push(...Object.values(childChunkFileMap)) + // Add modern only chunks into the main compilation + compilation.chunks.push( + ...Object.values(childChunkFileMap), + ...unnamedChunks + ) - // Place modern only chunk inside the right entry point + // Place modern only (unmerged) chunks inside the right entry point compilation.entrypoints.forEach((entryPoint, entryPointName) => { const childEntryPoint = childCompilation.entrypoints.get(entryPointName) childEntryPoint.chunks.forEach((chunk: compilation.Chunk) => { - if (childChunkFileMap.hasOwnProperty(chunk.name)) { + if ( + // Add null named dynamic chunks since they weren't merged + chunk.name === null || + childChunkFileMap.hasOwnProperty(chunk.name) + ) { entryPoint.chunks.push(chunk) } })