SolidZORO / next-plugin-antd-less

🎩 Use Antd (Less) with Next.js v12, Zero Dependency on other Next-Plugins.
MIT License
345 stars 48 forks source link

Production build missing css #18

Closed rriski closed 3 years ago

rriski commented 3 years ago

Hey, I'm trying to replace @zeit/next-less with this plugin. Everything works fine in development but production build is missing css for some components. For example Button has css but Table css does not get included in the css bundle.

next.config.js:

require("@app/config");
const compose = require("lodash/flowRight");
const { locales, defaultLocale } = require("./i18n.js");
const AntDDayjsWebpackPlugin = require("antd-dayjs-webpack-plugin");

if (!process.env.ROOT_URL) {
  if (process.argv[1].endsWith("/depcheck")) {
    /* NOOP */
  } else {
    throw new Error("ROOT_URL is a required envvar");
  }
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
(function (process = null) {
  // You *must not* use `process.env` in here, because we need to check we have
  // those variables. To enforce this, we've deliberately shadowed process.
  module.exports = () => {
    const fs = require("fs");
    const path = require("path");

    const withAntdLess = require("next-plugin-antd-less");
    const lessToJS = require("less-vars-to-js");

    // Where your antd-custom.less file lives
    const themeVariables = lessToJS(
      fs.readFileSync(
        path.resolve(__dirname, "../assets/antd-custom.less"),
        "utf8"
      )
    );
    const withNextTranslate = require("next-translate");

    return compose(
      withAntdLess,
      withNextTranslate
    )({
      poweredByHeader: false,
      distDir: `../.next`,
      trailingSlash: false,
      lessVarsFilePath: path.resolve(__dirname, "../assets/antd-custom.less"),
      modifyVars: themeVariables,
      i18n: {
        locales,
        defaultLocale,
      },
      webpack(config, { webpack, dev, isServer }) {
        const makeSafe = (externals) => {
          if (Array.isArray(externals)) {
            return externals.map((ext) => {
              if (typeof ext === "function") {
                return (context, request, callback) => {
                  if (/^@app\//.test(request)) {
                    callback();
                  } else {
                    return ext(context, request, callback);
                  }
                };
              } else {
                return ext;
              }
            });
          }
        };

        const externals =
          isServer && dev ? makeSafe(config.externals) : config.externals;

        return {
          ...config,
          plugins: [
            ...config.plugins,
            new webpack.DefinePlugin({
              /*
               * IMPORTANT: we don't want to hard-code these values, otherwise
               * we cannot promote a bundle to another environment. Further,
               * they need to be valid both within the browser _AND_ on the
               * server side when performing SSR.
               */
              "process.env.ROOT_URL":
                "(typeof window !== 'undefined' ? window.__GRAPHILE_APP__.ROOT_URL : process.env.ROOT_URL)",
              "process.env.T_AND_C_URL":
                "(typeof window !== 'undefined' ? window.__GRAPHILE_APP__.T_AND_C_URL : process.env.T_AND_C_URL)",
              "process.env.SENTRY_DSN":
                "(typeof window !== 'undefined' ? window.__GRAPHILE_APP__.SENTRY_DSN : process.env.SENTRY_DSN)",
            }),
            new webpack.IgnorePlugin(
              // These modules are server-side only; we don't want webpack
              // attempting to bundle them into the client.
              /^(node-gyp-build|bufferutil|utf-8-validate)$/
            ),
            new AntDDayjsWebpackPlugin(),
          ],
          externals: [
            ...(externals || []),
            isServer ? { "pg-native": "pg/lib/client" } : null,
          ].filter((_) => _),
        };
      },
    });
  };
})();

.babelrc:

{
  "presets": ["next/babel"],
  "plugins": [
    [
      "import",
      {
        "libraryName": "antd",
        "style": true
      }
    ],
    [
      "import",
      {
        "libraryName": "lodash",
        "libraryDirectory": "",
        "camel2DashComponentName": false
      },
      "lodash"
    ]
  ],
  "env": {
    "development": {
      "presets": [
        [
          "next/babel",
          {
            "preset-env": {
              "targets": {
                "node": "current",
                "browsers": "last 2 chrome versions"
              }
            }
          }
        ]
      ]
    }
  }
}

_app.tsx:

...
import "antd/dist/antd.less";
import "../styles.less";
...

styles.less

@import "~antd/lib/style/themes/default.less";

package.json

{
  "dependencies": {
    "antd": "4.11.2",
    "antd-dayjs-webpack-plugin": "^1.0.6",
    "dayjs": "1.10.4",
    "less": "^4.1.1",
    "less-vars-to-js": "^1.3.0",
    "next": "^10.0.6",
    "next-plugin-antd-less": "^0.1.4",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "webpack": "^5.19.0"
  },
  "devDependencies": {
    "babel-plugin-import": "^1.13.3",
    "cross-env": "^7.0.3",
    "jest": "^26.6.3"
  }
}

Any ideas what might be wrong with this setup?

SolidZORO commented 3 years ago

Is it a setting elsewhere that affects it? For example, the sideEffect of package.json.

Can you try your code with a simple project at https://github.com/SolidZORO/mkn ?

rriski commented 3 years ago

Alright I think I figured what the issue is but no solution yet. My repo is organized with yarn workspaces and antd Table is imported only in @app/components an not in @app/client (next.js app that contains next.config.js). @app/client imports my custom table component that utilizes antd table import { ServerPaginatedTable } from "@app/components";. If I include import "antd/lib/table/style"; in _app.tsx the table styles are bundled into the final bundle. I also tried to use next.js's webpack 5 support by specifying future: { webpack5: true }, in next.config but I get an error TypeError: Cannot read property 'findIndex' of undefined thrown from next-plugin-antd-less/index.js:45:46.

rriski commented 3 years ago

Coming back to the webpack 5 issue. Specifying future: { webpack5: true }, in https://github.com/SolidZORO/mkn project next.config.js break at line rules[1].oneOf because of https://github.com/vercel/next.js/blob/8f21c283b27357dbb2aebe94587901b6c7f4fe64/packages/next/build/webpack-config.ts#L892. The oneOf definition is at index 2 if webpack 5 is enabled.

Reproduction:

Specify future: { webpack5: true }, in https://github.com/SolidZORO/mkn next.config.js.

Would you consider adding support for next.js webpack 5 mode? next-transpile-modules does it via a unstable_webpack5 flag.

SolidZORO commented 3 years ago

I tried it briefly and found a lot of problems.

so I'm not going to support webpack5 now, I'll wait for webpack5 to become the default and then I'll support it.

rriski commented 3 years ago

I was also investigating webpack 5 issues a bit but when I downgraded to using webpack 4 I kep getting

error - /node_modules/antd/lib/style/index.less ((webpack)/css-loader/cjs.js??ref--5-oneOf-3-1!(webpack)/postcss-loader/cjs.js??ref--5-oneOf-3-2!(webpack)/resolve-url-loader??ref--5-oneOf-3-3!/Users/timo/code/prodeko/ilmo/node_modules/less-loader/dist/cjs.js??ref--5-oneOf-3-4!/Users/timo/code/prodeko/ilmo/node_modules/antd/lib/style/index.less)
(RUN) @app/server: TypeError: this.getOptions is not a function

I figured this was due to changes in less-loader@8.0.0 since yarn resolutions

  "resolutions": {
    "less-loader": "7.3.0"
  },

Compiled correctly for me. On their Github page, less-loader notes that minimum webpack version for less-loader@8.0.0 is 5: https://github.com/webpack-contrib/less-loader/releases/tag/v8.0.0. less-loader@8.0.0 is marked as a dependency of this package.

SolidZORO commented 3 years ago

yes! this plugin update less-loader to 8.0.0 at today.

u can try yarn install --force

etabard commented 3 years ago

Hi @rriski, have you found a solution ? I’m having the same issue using workspaces and postgraphile starter. Thanks for your help !