vercel / next.js

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

Work with antd? #484

Closed thebetterjort closed 7 years ago

thebetterjort commented 7 years ago

I'm trying to get nextjs to work with antd but get

"You may need an appropriate loader to handle this file type."

What do I need to do in order to get these things working together? Thanks.

arunoda commented 7 years ago

May be that's related to importing .css files. Currently, we don't support importing custom modules.

Even if you've added a correct webpack-loader, it won't work since SSR env cannot import that.

thebetterjort commented 7 years ago

https://github.com/ant-design/babel-plugin-import#via-babelrc

This is no help then. Is custom modules on the map, or not so much because of SSR?

arunoda commented 7 years ago

We wanted to support it. But I think we need to work a bit harder for that. So, that's after a priority after 2.0

thebetterjort commented 7 years ago

Thanks Arunoda! I seem to have followed you from meteor. Nice to see you around.

sedubois commented 7 years ago

Is is still planned for after 2.0? Should this be reopened then?

soulmachine commented 7 years ago

+1 for antd

liadbiz commented 7 years ago

feature supported now? I am tring to use antd with nextjs

timneutkens commented 7 years ago

@liadbiz have a look here https://github.com/zeit/next.js/issues/544

liadbiz commented 7 years ago

@timneutkens thanks. I will give feedback after tring.

jozanza commented 7 years ago

Just thought I'd chime in since this seems to be a bit of a tricky issue in next.js. Anyhow here's how I'm able to use antd's css imports in my project: https://github.com/zeit/next.js/issues/544#issuecomment-280190145

AugustinLF commented 7 years ago

@jozanza do you have a working example of this? Where you render an antd component? And how you then import the css? Because I can't make it work :'(

blakedietz commented 7 years ago

@AugustinLF I've figured out an example if you're interested. I haven't made a really in depth application so I don't know if any other problems exist yet, but I've been able to import a Button component and have it display.

If you clone this example: https://github.com/zeit/next.js/tree/master/examples/with-global-stylesheet

Then import that antd styling like so in an app level component.

components/App.js

import styles from 'antd/dist/antd.css';

export default ({ children }) => (
  <main>
    <style dangerouslySetInnerHTML={{ __html: styles}} />
    {children}
  </main>
)

Then in any of your pages, I'm using index.js as an example:

import App from '../components/App'
import Header from '../components/Header'
import withData from '../lib/withData'

import { Button } from 'antd';

export default withData((props) => (
  <App >
    <Header pathname={props.url.pathname} />
    <Button>Test</Button>
  </App>
))

And voila you have an antd styled button. Again, I'm still learning to see if this works without issue, so I'm going to continue playing with this solution. Unfortunately I haven't found a solution for importing a single component's set of styles at a time so this will be kind of expensive over the network.

AugustinLF commented 7 years ago

Yes, thank you, it worked out for me!

MrLoh commented 7 years ago

Yeah, that works pretty well. You can also enable global imports like this import { Button, Input, Form } from 'antd' by using the babel-plugin-import. Loading all the CSS is not such a big issue, since it is just 43 KB gzipped.

PhanXuanThuan commented 7 years ago

484

rdewolff commented 7 years ago

Do you recommend the approach from @blakedietz ?

MrLoh commented 7 years ago

I compiled the less files in the static folder, since I needed my own theming and then just added a style tag, but the end result is about the same I think

ouxu commented 7 years ago

OK, I solved it, but you must to import the whole css, such as me, I import the css file in Head. Just see the code:

layout/index.js

import Head from 'next/head'
export default ({children}) => (
  <div>
    <Head>
      <link rel='stylesheet' href='http://cdn.bootcss.com/antd/2.9.3/antd.css' />
    </Head>
    {children}
  </div>
)

pages/index.js

import React from 'react'
import Layout from '../layout'
import { Button } from 'antd'
export default () => (
  <Layout>
    <Button type="primary">Primary</Button>
  </Layout>
)

And to import on demand, we should add babel plugins, please run npm install -D babel-plugin-import at first.

.babelrc

{
  "presets": ["next/babel"],
  "plugins": [
    ["import", {
           "libraryName": "antd",
           "style": false
        }]
  ]
}

That's all, good luck to you!

viztor commented 7 years ago

This issue still exists today. it seems SSR just won't support global css import.

Ikhan commented 7 years ago

I'm also having this issue. I'm trying to import semantic.min.css but couldn't. Throws me an error.

thebetterjort commented 7 years ago

Next.JS with Ant design example

tconroy commented 7 years ago

any way to do it without linking to an external stylesheet? Would like to keep everything in JS if possible..

kriscarle commented 6 years ago

I was able to theme antd by using https://github.com/erasmo-marin/styled-jsx-plugin-less

couple of caveats: 1) It forces you to use less in all of your styled jsx. I'm new to less and discovered there are a few gotchas like needing to wrap certain css lines like height: ~"calc(100% - 50px)" 2) you still have to load the entire style (Possibly there is a way to deconstruct antd's less and only import what you need, maybe following how they do it in babel-import-plugin)

Here is my .babelrc

{
  "presets": [
    [
      "next/babel",
      {
        "styled-jsx": {
          "plugins": [
            "styled-jsx-plugin-less"
          ]
        }
      }
    ]
  ],
  "plugins": [
    "transform-decorators-legacy",
    [
      "import",
      {
        "libraryName": "antd",
        "style": false
      }
    ]
  ]
}

Then in my layout component below the next.js <Head></Head> tag I have

<style jsx global>{`
  @import "./node_modules/antd/dist/antd.less";
  @primary-color: red;
 `}
</style>
truca commented 6 years ago

this works as a charm: https://github.com/hanpama/next-with-antd

  1. add packages

    yarn add antd babel-plugin-inline-import
  2. configure babelrc: add the .babelrc file from that project

  3. copy the pages/index.js file to that same path in your project

  4. restart next

  5. reopen localhost:3000

ghost commented 6 years ago

@truca why didn't you make use of this? isn't this possible in latest next? https://ant.design/docs/react/getting-started#Import-on-Demand

I suppose that inline approach imports entire ant stylesheet, will that not affect loading performance?

kriscarle commented 6 years ago

Just tested antd with the new next-less plugin for next v5.x and it works great when pointing it directly to antd/dist/antd.less

Only note is that antd isn't compatible with the new less v3.x yet, had to revert to v2.7

This is still including the entire style. @crushy26 yes, since the latest next now runs webpack on the server side, it should be possible to use babel-plugin-import I'll try that next.

amrdraz commented 6 years ago

@kriscarle do you have an example of what you did?

and3rsonsousa commented 6 years ago

Look at the of this example and you can make it work.

https://github.com/zeit/next.js/tree/canary/examples/with-ant-design

kriscarle commented 6 years ago

@amrdraz here is a Gist with my current config, it supports a custom theme, but still includes the entire style: https://gist.github.com/kriscarle/d3136e9b15634846036397409bf98214

@and3rsonsousa thanks! I hadn't noticed that the example was updated.

It is still using the css option in babel-plugin-import not the less option, so won't support custom themes but I think it is getting close. When I get a chance, I'll look into whether I can get the less theming working using the new example.

and3rsonsousa commented 6 years ago

You just have to see the example on Ant site abou using less. I did it and it was very easy to configure.

brandonmp commented 6 years ago

i've tried a dozen different ways of achieving antd + next without requiring the entire css file. the only way i've managed to make it work so far is (might require styled-components or similar):

  1. enable inline css imports w/ the babel-plugin-inline-import:

    [
            "inline-import",
            {
                "extensions": [".css"]
            }
        ],
  2. Create a new directory with 1 file for each antd component, eg components/antd/Table.js

  3. import (a) the JS imported from antd/lib/*, (b) the css from the components style folder, and (c) injectGlobal from styled-components

  4. Inject the css into the global scope and export. so this is what table looks like:

import Table from 'antd/lib/table';
import Styles from 'antd/lib/table/style/index.css';
import { injectGlobal } from 'styled-components';

injectGlobal`${Styles}`;
export default Table;

Now, ideally, we could do this:

import Table from 'antd/lib/table';
import Styles from 'antd/lib/table/style/index.css';
import styled from 'styled-components';

export default styled(Table)`${Styles}`;

... which would scope styles locally, which is great. but as of next 3/4 (when I set this up), something was stopping that from working. So, I used injectGlobal.

The big pro with this approach is that all the CSS is inlined, so it lands in the client rendered and ready (also helps w/ page speed, per google pagespeed insights).

The cons are that it's a pain in the ass to set up, plus a few gotchas:

  1. some components call for styles from some other components. eg Slider uses styles from lib/slider and lib/tooltip, and Form requires grid/style, so in each case you've gotta import both (protip: Transfer uses styles from 5 diff't components)

  2. some stuff, like animations, doesn't live in any specific component's css, so i had to extract those and import them separately (also using injectGlobal). here's a gist with all the animations, etc.

  3. You probably want to import the antd icon font separately as well, since a lot of components rely on it

Oh, and if you're using typescript, don't forget to declare .css imports:

declare module '*.css' {
    const styles: string;
    export default styles;
}
delikat commented 6 years ago

i got modular antd imports working with babel-plugin-import and less themes: https://gist.github.com/delikat/d50cf9c8bce8b8f469a8eaacab170ac3

so far i've been seeing decent size improvements vs. including the entire antd less file (especially minified). you can configure theme overrides with modifyVars, though note that you lose css HMR this way. if you want HMR while developing a theme you could import a simple less file like:

@import "~antd/dist/antd.less";
@primary-color: #E27AD3;

then remove it and move your overrides over to modifyVars when you're ready to deploy.

giautm commented 6 years ago

@delikat :Hi, There is an example with Antd + LESS. 😄 https://github.com/zeit/next.js/blob/canary/examples/with-ant-design-less/next.config.js

kriscarle commented 6 years ago

@delikat Awesome, thank you for figuring it out! I was completely defeated by this, too much Webpack magic required :)

@giautm in your example, it looks like the next-less plugin is still importing the entire style file? Probably fine for most people and definitely is a much cleaner config in Next. The babel-plugin-import + modifyVars config is the one we've been trying to crack. It filters the built css to only what is needed for the imported components. Though looks like it requires a lot more hacking of the default webpack config, so probably much more likely to break in future versions.

delikat commented 6 years ago

Actually it looks like we can simplify the required custom config by following the with-ant-design example's lead and overriding require's loader for .less files when running on the server. I've updated the gist above as well 🐱

giautm commented 6 years ago

@delikat hi, your gist ran into this error on Production start, look like it was not processed by less-loader in build steps.

{ /Users/admin/xxxx/node_modules/antd/lib/style/index.less:1
(function (exports, require, module, __filename, __dirname) { @import "./themes/default";
                                                              ^

SyntaxError: Invalid or unexpected token
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:152:10)
    at Module._compile (module.js:624:28)
    at Object.Module._extensions..js (module.js:671:10)
    at Module.load (module.js:573:32)
    at tryModuleLoad (module.js:513:12)
    at Function.Module._load (module.js:505:3)
    at Module.require (module.js:604:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/admin/xxxx/node_modules/antd/lib/button/style/index.js:3:1) sourceMapsApplied: true }
delikat commented 6 years ago

hi @giautm, yes it looks like overriding require.extensions doesn't work in prod. I did a quick test and the original solution I posted, excluding antd files from webpack externals, seems to work fine after build and start. I've updated the gist to reflect that.

giautm commented 6 years ago

@delikat It's still not working. dir was not defined in your gist.

Update: Yah, I found it in the first version of your gist. It's worked

tanint commented 6 years ago

@delikat It work, big thank 👍

Vi-jay commented 6 years ago

@delikat It work,thx,but cssModules can't work again !

Enalmada commented 6 years ago

I tried creating a few more pages following the with-ant-design/index.js pattern and the css fails to load when you click the new pages. (with-ant-design-less didn't seem to have this problem) Could someone confirm I am not crazy that the with-ant-design example pattern has css loading issues if add new antd components to new pages and click around? I don't want new users to hit a brick wall when they try to scale out the example to more pages.

I assume the "transform-decorators-legacy" stuff in package.js and .babelrc is no longer necessary with next6 because next6 uses babel7? I would appreciate if someone who knows can confirm/deny that before I do push request to remove something I don't understand.

The example code would be better starting point for new users if it was using modular imports...antd css is just too big for production. Just adding antd dependency made my release zip go from 20m to 50m (insert swearing here). The example from @delikat seems to work...anyone object to it being part of the example? Note that I had some trouble using it with next 6 so my fixes are here with notes in comments: https://gist.github.com/Enalmada/c0a83bbc639aae5d4504527a0fe18f41 @timneutkens Can next.js provide a better more programatic way to get "antd" into the config.externals.push section? It is extremely brittle the way it has to be done now. Could next.js provide a way we can call the webpack.js/externalsConfig function with an argument list containing "antd"?

So why does HMR not work with this solution? Could someone elaborate on that please? I am curious if it is a solvable problem? Until then, to get modular import performance and have hot reloading in dev...is there a better solution than this: assets/styles.less (explicit reminder here to remove antd.less from the styles.less file) @import "./antd-custom.less"; asserts/antd.less @import "~antd/dist/antd.less"; index.js (load the full css in development to get HMR) ... if (process.env.NODE_ENV === 'development') { require('./asserts/antd.less') } ...

chen900112 commented 6 years ago

I asked for more help #5180

tavurth commented 5 years ago

Look at the of this example and you can make it work.

https://github.com/zeit/next.js/tree/canary/examples/with-ant-design

Thank you, this helped me get it working!

balazsorban44 commented 2 years ago

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.