vercel / next.js

The React Framework
https://nextjs.org
MIT License
124.99k stars 26.7k forks source link

Update Ant Design Examples for New CSS Support (9.2) #9830

Closed poyiding closed 4 years ago

poyiding commented 4 years ago

import ant-design library throw error

can you provide an example import ant-design use [RFC] css support? thanks. when i use [RFC] css support and import ant-design library, it throw error :

./node_modules/antd/lib/button/style/index.css
Global CSS cannot be imported from files other than your Custom <App>. Please move all global CSS imports to pages/_app.js.

here is my next-config.js

module.exports = {
    experimental: {
      css: true
    },
  }
yufengwang commented 4 years ago

Maybe not support css from node_modules, I guess.

poyiding commented 4 years ago

Maybe not support css from node_modules, I guess.

if you don't use [RFC] css support , you can support css from node_modules with-css plugin.

timneutkens commented 4 years ago

Linking to #8626

kachkaev commented 4 years ago

I’d be also interested in seeing this. Our teams use antd with next-css/next-less and some hacks on top from the Next.js examples folder. That setup is quite clumsy and fragile. I’m looking forward to switching to the build-in css support, but have no clue how to deal with less in this case.

antd is a pretty popular ui framework, so I guess quite a lot of devs will benefit from a new example.

stephankaag commented 4 years ago

Has anyone got ant-design working with Next 9.2 yet? (without @zeit/next-css)

jonahfang commented 4 years ago

@stephankaag, I have used withLess to use antd v4.0.0.rc1, it works!

ChuckJonas commented 4 years ago

I'm still seeing issues with antd 4.0.

Configuration is similar to [https://levelup.gitconnected.com/lets-create-a-project-with-nextjs-antd-and-deploy-with-now-sh-e38772348312|this guide]

stephankaag commented 4 years ago

@stephankaag, I have used withLess to use antd v4.0.0.rc1, it works!

Of course, because that combination always worked. I am trying to make things work WITHOUT @zeit/next-css or @zeit/next-less.

dpyzo0o commented 4 years ago

Anyone has successfully integrated next 9.2 with ant design? (without next-css plugin)

chemicalkosek commented 4 years ago

@stephankaag The combination works very well (I'm using withCss combined with withLess and custom less variables), but how is your bundle size? I have migrated to antd4. Seems like the tree shaking doesn't work as expected from v4. I'm having more than 1,3mb bundle size, where most of it are the antd icons. According to this https://github.com/ant-design/babel-plugin-import/issues/402 the "libraryDirectory": "es" is necessary (the official with-ant-less example doesn't have it). But adding this gives me the following error:

[ error ] /home/maciek/Dokumenty/websites/bookingapp/frontend/node_modules/antd/es/notification/index.js:3
import * as React from 'react';
       ^

SyntaxError: Unexpected token *
    at Module._compile (internal/modules/cjs/loader.js:723:23)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Module.require (internal/modules/cjs/loader.js:692:17)
    at require (internal/modules/cjs/helpers.js:25:18)
    at Object.antd/es/notification (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:10975:18)
    at __webpack_require__ (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:23:31)
    at Module../lib/withData.js (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:8200:78)
    at __webpack_require__ (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:23:31)
    at Module../pages/_app.js (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:10614:71)
    at __webpack_require__ (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:23:31)
    at Object.0 (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:10754:18)
    at __webpack_require__ (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:23:31)
    at /home/maciek/Dokument
DuncanAForbes commented 4 years ago

@stephankaag The combination works very well (I'm using withCss combined with withLess and custom less variables), but how is your bundle size? I have migrated to antd4. Seems like the tree shaking doesn't work as expected from v4. I'm having more than 1,3mb bundle size, where most of it are the antd icons. According to this ant-design/babel-plugin-import#402 the "libraryDirectory": "es" is necessary (the official with-ant-less example doesn't have it). But adding this gives me the following error:

[ error ] /home/maciek/Dokumenty/websites/bookingapp/frontend/node_modules/antd/es/notification/index.js:3
import * as React from 'react';
       ^

SyntaxError: Unexpected token *
    at Module._compile (internal/modules/cjs/loader.js:723:23)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Module.require (internal/modules/cjs/loader.js:692:17)
    at require (internal/modules/cjs/helpers.js:25:18)
    at Object.antd/es/notification (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:10975:18)
    at __webpack_require__ (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:23:31)
    at Module../lib/withData.js (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:8200:78)
    at __webpack_require__ (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:23:31)
    at Module../pages/_app.js (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:10614:71)
    at __webpack_require__ (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:23:31)
    at Object.0 (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:10754:18)
    at __webpack_require__ (/home/maciek/Dokumenty/websites/bookingapp/frontend/.next/server/static/development/pages/_app.js:23:31)
    at /home/maciek/Dokument

@chemicalkosek did you manage to resolve this? I've been running into the exact same issue on Nextjs 9.2.1

jeromemmiranda commented 4 years ago

Anyone manage to resolve this issue?

gjvpaet commented 4 years ago

Any updates to this issue?

i-tengfei commented 4 years ago

My solution:

yarn add esm
"scripts": {
    "dev": "NODE_OPTIONS=\"-r esm\" next",
    "build": "NODE_OPTIONS=\"-r esm\" next build",
    "start": "NODE_OPTIONS=\"-r esm\" next start"
}
chemicalkosek commented 4 years ago

@i-tengfei Wow, it's working! Thank you very much!

ChuckJonas commented 4 years ago

@i-tengfei are you using the same configuration as the example?

If not, mind posting your next.config & babelrc?

chemicalkosek commented 4 years ago

Btw I'm not using the new CSS support. What's working is next with antd4 tree shaked (tree shaking never worked with antd in the official example, because of the lack of "libraryDirectory":"es"). Bundle size cut about 700-800kb I believe. I'm still using withCss and withLess tho.

ChuckJonas commented 4 years ago

@chemicalkosek do you still see:

chunk styles [mini-css-extract-plugin]
Conflicting order between

with your setup?

chemicalkosek commented 4 years ago

Yes, I do, but afaik that's just a warning and everything works just fine. I have once researched this issue and I believe it's because you have in one component:

import { Button, Input } from 'antd'

and in another component:

import { Input, Button } from 'antd'

Supposedly it's what's creating this issue, but I'm not really sure of it You can hide those warnings, but I didn't try. I'll try tomorrow though, those can be pretty annoying. Source 1: https://github.com/webpack-contrib/mini-css-extract-plugin#remove-order-warnings Source 2: https://github.com/webpack-contrib/mini-css-extract-plugin/issues/250 I'm very happy about the tree shaking now :) And with antd4 the icons are no longer included as they were with antd3, where the icons made like half of antd3 size. You can import icons selectively now.

ChuckJonas commented 4 years ago

Unfortunately, my experience is it's not just a warning you can just ignore. I've seen issues with components not getting styled as I've added more antd components to the page. Happens very inconsistently. Organizing imports consistently doesn't make it go away either

chemicalkosek commented 4 years ago

You mean in dev? Yes, I'm experiencing sometimes in dev that the components are not styled. Not very often. Works after I refresh the page. Do you have the same problem in production? In production after next build everything works fine for me. Even though I have the same 'conflicting order' messages in build logs.

ChuckJonas commented 4 years ago

@chemicalkosek I feel like I have seen it in production, but I'm not 100% sure...

Hopefully you're right

JesperWe commented 4 years ago

FWIW this happens intermittently to us in production builds as well.

ssteiger commented 4 years ago

removed

poyiding commented 4 years ago

@ssteiger we are talking about not use @zeit/next-css plugin.

ssteiger commented 4 years ago

Ups sorry. Wrong thread.

marcelobaez commented 4 years ago

has anybody got working ant design 4 (less) + nextjs 9.2 + avoid conflicting order?

oceandrama commented 4 years ago

Also, would like to see example with @ant-design/pro-layout. Is anybody see working repo?

ImAbdullahJan commented 4 years ago

Ant.design@4 working with next@9.3 without next.config.js.

My code in pages/_app.js is:

import "../node_modules/antd/dist/antd.css";
export default ({ Component, pageProps }) => <Component {...pageProps} />;

package.json is:

"dependencies": {
    "antd": "^4.0.2",
    "next": "^9.3.0",
    "react": "^16.13.0",
    "react-dom": "^16.13.0"
  }
oceandrama commented 4 years ago

@ImAbdullahJan Yes, it works but with loading full css-bundle. Is it possible to use babel-plugin-import without @zeit/withCss?

mit123suki commented 4 years ago

any clue how do i deal with less(ant) with new built-in support for css and sass?

coderdix commented 4 years ago

awww i should not have upgraded. broke my app above my pay grade

OliverRudoll commented 4 years ago

awww i should not have upgraded. broke my app above my pay grade

same here

timneutkens commented 4 years ago

@OliverRudoll @coderdix what broke? built-in CSS/Sass support is disabled when you use @zeit/next-css so the update should be non-breaking.

OliverRudoll commented 4 years ago

@OliverRudoll @coderdix what broke? built-in CSS/Sass support is disabled when you use @zeit/next-css so the update should be non-breaking.

Thanks for asking Tim. Disclaimer: It's my first year with next and I'm not completely into the concepts.

What I can tell you is that the following configuration works with the "very" old version (next 9.0.4). When I update to 9.2.2 or 9.3 and stop using the external Sass/Css PlugIns in the config I get a problem with the Babel configuration.

I rolled back to the older version for now because of the lack of time - I will try to try the update again and describe my problem in detail asap.

next.config.js

const withTm = require('next-transpile-modules')([
  'core',
  'additional',
  'shared',
]);
module.exports = withTm(
  withFonts(
    withImages(
      withVideos(
        withSass({
          ...withCss({
            typescript: {
              ignoreDevErrors: true
            },
            publicRuntimeConfig: {
              API_ROOT: "http://localhost:8000/api/",
              env: process.env.NODE_ENV
            },
            webpack: (config, { isServer }) => {
              if (isServer) {
                const antStyles = /antd\/.*?\/style\/css.*?/;
                const origExternals = [...config.externals];
                config.externals = [
                  (context, request, callback) => {
                    if (request.match(antStyles)) return callback();
                    if (typeof origExternals[0] === "function") {
                      origExternals[0](context, request, callback);
                    } else {
                      callback();
                    }
                  },
                  ...(typeof origExternals[0] === "function"
                    ? []
                    : origExternals),
                ];
                config.module.rules.unshift({
                  test: antStyles,
                  use: "null-loader",
                });
              }
              config.devtool = "eval-source-map";
              return config;
            },
            distDir: "../../dist/functions/next",
          }),
          cssModules: true,
        })
      )
    )
  )
);

babel.config.js

module.exports = function(api) {
  api.cache(true);
  const presets = ["next/babel"];
  const plugins = [
    ['styled-components'],
    ['import', { libraryName: "and", style: "css" }],
  ];
  return {
    presets,
    plugins,
  };
};
mit123suki commented 4 years ago

@chemicalkosek @ChuckJonas what's your build size say for a typical form or for the given with-ant-design example? Can you purge ant css successfully?

ChuckJonas commented 4 years ago

@mit123suki In my case, I'm more concerned with broken styles than page size, so my solution was just to include the entire stylesheet in _app.ts

//due to chunk styles [mini-css-extract-plugin] -> Conflicting order between ... error
// once resolved, delete this file and uncomment code in .babelrc to use antd plugin
import 'antd/dist/antd.less';
export default ({ Component, pageProps }) => <Component {...pageProps} />;

With this, my css chuck seems to be roughly ~62kb gzipped. I'm pretty much relying on 99% of the antd styles for my app.

chemicalkosek commented 4 years ago

@mit123suki Running build-analyze without esm is currently erroring out for me (even when I comment out libraryDirectory), but the build size is 880kb and with esm and libraryDirectory: es it's 720kb gzipped (not a small app). But strangely now even without esm I don't see the whole antd icons package included which I believe accounted for hundreds of kbs. Maybe because it's erroring out, I don't see it in the bundle and the numbers are now not accurate.

But definitely without esm and "libraryDirectory": "es" I can see the whole antd package included (strangely - without icons right now). With esm it's tree shaked.

Without "libraryDirectory": "es" (biggest chunk with antd):

Zaznaczenie_883

With "libraryDirectory": "es" (antd is now tree shaked not showing as the biggest chunk)

Zaznaczenie_884

kdenz commented 4 years ago

@mit123suki Thanks! Following your setup in https://github.com/zeit/next.js/pull/11837 made it work on next.js 9.3.4

mattcarlotta commented 4 years ago

@mit123suki The esm transpiling/compiling seems like a bit of a heavy-handed approach and may not produce chunks that work for older browsers.

That said, I was able to reduce the bundle size from:

to:

by utilizing the antd/lib folder...

babel.config.js (without a custom next config, style: css should be removed and instead, you should manually import the entire library: import "antd/dist/antd.min.css"; within a custom _app.js page file)

module.exports = api => {
  api.cache(true);
  return {
    presets: ["next/babel"],
    plugins: [
      ["import", { libraryName: "antd",  libraryDirectory: "lib", style: "css" }],
      ["import", { libraryName: "@ant-design/icons", libraryDirectory: "lib/icons", camel2DashComponentName: false }, "@ant-design/icons"],
    ],
  };
};

The above configuration doesn't require esm transpiling/compiling. However, the es folder is still being required by webpack in the production build despite it not being utilized/required AT ALL and even when it's been aliased to an empty file (see post below for why this can happen).

mattcarlotta commented 4 years ago

After hours and hours of debugging, the root cause of the whole es package import can be either not utilizing the babel-import-plugin with the ant/lib package OR using the next/dynamic package incorrectly.

If you use the babel.config.js I've shown above and you don't use dynamic, then your production build shouldn't include the antd/es folder nor should it need to compile/transpile ant's esm packages.

However, it appears that some ant imports (like Table) break tree-shaking icons, and it will import the entire @ant-icons library despite using the babel-plugin-import. To mitigate this issue, you'll want to manually export the icons you need from a user-defined file and then alias the @ant-icons package to this file in the next.config.js webpack config (NOTE: Unfortunately, if you need to use additional icons from the @ant-icons library, or use additional antd components, then you'll need to export any required icons). The working example below includes how to accomplish this...

Working Example:

  1. Clone example repo: git clone git@github.com:mattcarlotta/antd-example.git
  2. Install dependencies: yarn
  3. Run yarn outputs to traverse through the different branches: master, dynamic, and unoptimized to build production files and to display the resulting chunk graphs.

Results

Directly importing Table and aliasing icons (master branch):

import { Table } from "antd";

Results in this graph (parsed: 797.19 KB)


Using dynamic to import the ant/lib/table and aliasing icons (dynamic branch):

import dynamic from "next/dynamic";
import "antd/lib/table/style/css.js"; // required, otherwise, no styles will be applied

const Table = dynamic(() => import("antd/lib/table"), { ssr: false });

Results in this graph (parsed: 805.73 KB):


Using dynamic on the whole package and not aliasing icons (unoptimized branch):

import dynamic from "next/dynamic";
import "antd/lib/table/style/css.js" // required, otherwise, no styles will be applied

const Table = dynamic(() => import("antd").then(mod => mod.Table), { ssr: false });

Results in this graph (parsed: 2.32 MB):

See post below for esm results.

mit123suki commented 4 years ago

Awesome work @mattcarlotta Yeah transpiling with esm is an overhead and i want to avoid too but tree-shaking seems to fail without es libdirectory and it requires esm. Also causing some error without it. Antd design system is complex loading the whole styles recursively, say for example, just create Button component and use less plugin and you can see the whole styles loaded. Fortunately babel-plugin-import helps to avoid this to some extent by explicitly importing the required components and its style using babel config. If you use css, then you also need to include the entire css file in _app, if not it breaks as every components depends on it. Purging css at this point also breaks so many problems hehe. My setup build size looks quite decent to me but again as you said esm transipiling overhead is the problems.

Your last example using component css.js import looks interesting. I'll check the repo :)

mattcarlotta commented 4 years ago

@mit123suki With the aid of the babel-plugin-import and a custom next webpack configuration, tree shaking (or at least only requiring what's necessary for the component to function properly) will work with the antd/lib folder, therefore, utilizing the antd/es (esm) folder may not be necessary.

Out of curiosity, what does the esm build output when only a Button is imported?

For example, importing just the Button component:

As shown here, it's only importing what's required in the antd/lib/button.js file:

mattcarlotta commented 4 years ago

Hmm... I'm on the fence about utilizing a heavy-handed approach for one package. That said, the results for utilizing the esm package, shown below, speak for themselves. However, there's a trade-off: Browser compatibility and transpile/compilation times.

Parsed size: 692.73 KB (~100kb reduction over using ant/lib master branch)

From a medium-sized personal project, here are some more results:

Click to expand esm results

 -----------------------------------------------------------------
| Compilation attempts                                            |
 -----------------------------------------------------------------
1st Build - Compiled successfully in 39472ms (total 51.09s)
2nd Build - Compiled successfully in 34971ms (total 49.71s)
3rd Build - Compiled successfully in 34368ms (total 49.34s)
4th Build - Compiled successfully in 34867ms (total 49.40s)
5th Build - Compiled successfully in 34071ms (total 49.58s)
 -----------------------------------------------------------------
| Results graph - Compiled successfully in 34863ms (total 56.36s) |
 -----------------------------------------------------------------
Server:
Stat: All (8.07 MB)
Parsed: All (11.28 MB)
Gzip: All (2.14 MB)
-
Client:
Stat: All (7.74 MB)
Parsed: All (2.8 MB)
Gzip: All (789.13 KB)
-
Ant Chunk Count: 96 (Total size: 282.74 KB)
Click to expand cjs results

 -----------------------------------------------------------------
| Compilation attempts                                            |
 -----------------------------------------------------------------
1st Build - Compiled successfully in 36334ms (total 43.72s)
2nd Build - Compiled successfully in 34878ms (total 42.51s)
3rd Build - Compiled successfully in 31138ms (total 42.10s)
4th Build - Compiled successfully in 31732ms (total 41.41s)
5th Build - Compiled successfully in 35435ms (total 43.92s)
 -----------------------------------------------------------------
| Results graph - Compiled successfully in 36166ms (total 57.03s) |
 -----------------------------------------------------------------
Server:
Stat: All (8.07 MB)
Parsed: All (11.28 MB)
Gzip: All (2.14 MB)
-
Client:
Stat: All (8.01 MB)
Parsed: All (2.94 MB)
Gzip: All (820.81 KB)
-
Ant Chunk Count: 204 (Total size: 1.05 MB)
chemicalkosek commented 4 years ago

In my current project, build is erroring out without esm and libraryDirectory: es on this:

> Build error occurred
/home/....../frontend/node_modules/antd/es/date-picker/generatePicker.js:36
import * as React from 'react';
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at compileFunction (<anonymous>)
    at wrapSafe (internal/modules/cjs/loader.js:1072:16)

I'm using this new addition to antd4 to replace moment.js with day.js: https://ant.design/docs/react/replace-moment

That's just a quick info, didn't investigate further, went back to esm for now as this is an in-production app

mattcarlotta commented 4 years ago

@chemicalkosek The problem is in the babel setup and displayed in the error:

.../....../.../.../antd/es/.../....js

Your babel config is targeting esm ("libraryDirectory": "es"). If you want to utilize cjs (or is it umd, didn't really look too closely) then utilize the babel-plugin-import to target lib ("libraryDirectory": "lib").

See above for babel config.

sebas-deedee commented 4 years ago

Any updates to this issue?

mattcarlotta commented 4 years ago

@sebas-deedee There isn't any way forward until next supports loading CSS from node_modules and that likely won't be supported because it currently may result in unordered CSS imports -- for example, loading an overrides.css file first, then a node_module/antd/component/style.css second -- which results in an inconsistent UI/UX. Until then, you have two options:

Option 1.) Use a custom babel and next configuration to load CSS from node_modules/antd/lib or from node_modules/antd/es folders on the client. The advantage is that you'll only import what's needed. The disadvantage is that you have to very granular in your imports. Meaning, you have to manually import the styles required for each component because on the initial page load, the server will not handle the CSS imports; therefore, the CSS must be imported inside the _app.js file. For example:

in your _app.js file:

import "antd/(lib|es)/radio/style/css.js" // antd component css
import "antd/(lib|es)/table/style/css.js" // antd component css
...etc
import "../styles/globals.css" // global css
import "../styles/overrides.css" // overrides css

and in a page or component file

import { Radio, Table } from "antd" // this will pick from "ant/lib" or "ant/es"

The result is that the style imports are consistently loaded in order by their import position and your production build is smaller because you're cherry-picking the components and CSS.

or

Option 2.) Copy/paste the entire ant.min.css from the node_modules/dist/ant.min.css into a global.css file. Then import that file into an _app.js file. The advantage is that you don't need a custom next config to import from node_modules; however, you'll still need to import the entire ant-design CSS library. Therefore, the disadvantage is that your production build will have a rather large CSS file that will only be utilized by whatever components you've imported -- the rest will just be dead-weight CSS.

in your _app.js file:

import "../styles/globals.css" // antd.min.css (global) css
import "../styles/overrides.css" // overrides css

and in a page or component file

import { Table } from "antd"

The result is that the style imports are consistently loaded in order by their import position, but the production build is larger because of the unutilized CSS.


Neither option is particularly developer-friendly/zero-config, as such, I'd hesitate to pull this into the official with-ant-design example.

That said, here's a working example of both options above utilizing next: ^9.3.5 with antd: ^4.1.4: 1.) Clone the example: git@github.com:mattcarlotta/next-antd-v4.git 2.) Install dependencies: yarn 3.) Run the first option by running: yarn dev 4.) Once done, terminate the process and type: git checkout globals 5.) Run the second option by running: yarn dev

pahaz commented 4 years ago

In my opinion, one of the best way to use antd with @ant-design/pro-layout is just to rename all your .css files to .less. LESS is backward compatible with CSS. In this way, you don't need to hack your babel config. It's an easy and less hackable way.

If you need NextJS + antd + @ant-design/pro-layout example, you can check this: https://github.com/8iq/nodejs-hackathon-boilerplate-starter-kit/tree/master/apps/_example04antpro (but, you should use .less extension for your .css files)

mattcarlotta commented 4 years ago

@pahaz Your example fails to build for production.