Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there an example for nextjs? #84

Closed
manuschillerdev opened this issue Dec 19, 2020 · 15 comments
Closed

Is there an example for nextjs? #84

manuschillerdev opened this issue Dec 19, 2020 · 15 comments
Labels
help wanted Extra attention is needed question Further information is requested

Comments

@manuschillerdev
Copy link

Hi!

I would love to try esbuild-loader with nextjs. Do you know any examples for a working configuration of nextjs with esbuild-loader?

@privatenumber privatenumber added help wanted Extra attention is needed question Further information is requested labels Dec 31, 2020
@kuasha420
Copy link

Hello,

I've tried to configure esbuild with nextjs and got some success. Here's the config.

const {
  ESBuildPlugin,
  // ESBuildMinifyPlugin
} = require('esbuild-loader');

const tsconfig = require('./tsconfig.json');

module.exports = {
  webpack: (config, { webpack, dev }) => {
    if (!dev) {
      config.plugins.push(
        new webpack.ProvidePlugin({
          /**
           *  Not sure why, This increases bundle size
           * when you would think the oposite would be true!
           */
          // __jsx: ['react', 'createElement'],
          // __fragment: ['react', 'Fragment'],
          React: 'react',
        }),
      );
      config.plugins.push(new ESBuildPlugin());
      const convertToESBuild = (obj) => {
        if (obj.loader === 'next-babel-loader') {
          return {
            loader: 'esbuild-loader',
            options: {
              loader: 'tsx',
              target: 'es2017',
              tsconfigRaw: tsconfig,
              // jsxFactory: '__jsx',
              // jsxFragment: '__fragment',
            },
          };
        }
        return obj;
      };

      const rule = config.module.rules[0];
      if (rule) {
        if (Array.isArray(rule.use)) {
          rule.use = rule.use.map((e) => {
            if (typeof e === 'object') {
              return convertToESBuild(e);
            }
            return e;
          });
        } else {
          rule.use = convertToESBuild(rule.use);
        }
      }

      /**
       *  Not sure why, but ESBuildMinifyPlugin makes the bundle larger.
       *
       * With Default Minimization:
       * Main Bundle: 239 KB
       * Largest Page: 122 KB
       *
       * With ESBuild Minification:
       * Main Bundle: 664 KB
       * Largest Page: 132 KB
       *
       * Probably a configuration error.
       */

      // // Remove Default TerserPlugin
      // config.optimization.minimizer.shift();

      // // Add ESBuild Minify
      // config.optimization.minimizer.unshift(
      //   new ESBuildMinifyPlugin({
      //     target: 'es2017',
      //     minify: true,
      //   }),
      // );
    }
    return config;
  },
};
  1. As you can notice, this is only for prod. In dev, the compilation works fine, but next router breaks.
  2. Haven't quite figured out how to configure Minimizer yet.
  3. Config inspired from ReferenceError: React is not defined in nextjs / blitzjs #62

@nandorojo
Copy link

I would also love to see an example with Next!

@lararosekelley
Copy link

Tried out a config based on your attempt @kuasha420 - noticed some CSS issues, namely styles coming from styled components. We use a mix of styled components as well as SCSS modules. Have you noticed any styling issues when comparing the build output from esbuild-loader vs the standard config?

@tdjsnelling
Copy link

I've also tested a similar config, but when built, getServerSideProps does not seem to be running when navigating to a SSR'd page via next router — but reloading or navigating directly to that pages URL causes it to run correctly. Did you test any SSR data-fetching pages?

@kuasha420
Copy link

I've also tested a similar config, but when built, getServerSideProps does not seem to be running when navigating to a SSR'd page via next router — but reloading or navigating directly to that pages URL causes it to run correctly. Did you test any SSR data-fetching pages?

I also experienced same behavior. My next step is to try swc and see if that's any different there.

@privatenumber
Copy link
Owner

I don't have any experience with Next.js, but I can try taking a look if one of you wants to provide a minimal reproduction repo.

Pure speculation but I also worry that replacing next-babel-loader might not be a good idea since it might not be identical to babel-loader and could be applying custom presets integral to Next.js.

@tdjsnelling
Copy link

I can try taking a look if one of you wants to provide a minimal reproduction repo.

I've modified the Next.js starter slightly here to demo the issue. In dev, you'll see that getServerSideProps works on page load and on router navigation. However after you yarn build and yarn start, you'll see that getServerSideProps only runs on page load.

@privatenumber
Copy link
Owner

Thanks @tdjsnelling

I added a Next.js example here: https://github.com/privatenumber/esbuild-loader-examples/tree/master/examples/next

Hope that helps.

Closing this as I think it's addressed but will re-open if there's anything more to do.

@nandorojo
Copy link

Thank you for sharing that! Do you have a confidence level for the stability of it? As in, do you think it’s safe to ship in production Next apps?

@privatenumber
Copy link
Owner

Every Next.js app is configured and used differently so I can't speak to that.

I don't know anything about your code, so even if I said I was confident, that won't mean much in the context of your app. You'll have to do your own due diligence of thorough testing to develop confidence.

If you run into any issues with the recommended Next.js configuration, let me know and I can try to help.

@hyoretsu
Copy link

The example seems to not work anymore in Next.js 11. Cannot set property 'loader' of undefined

@hnq90
Copy link

hnq90 commented Jul 9, 2021

@hyoretsu You should skip the loader patch for test: /.m?js/ pattern.

@Mi-lex
Copy link

Mi-lex commented Jul 15, 2021

To make it work with webpack 5, u can use replace next lines
https://github.com/privatenumber/esbuild-loader-examples/blob/8ddf91b7d67e38237dc68008452b7af570be50da/examples/next/next.config.js#L17
with

  if (jsLoader) {
    jsLoader.use = {
      ...jsLoader.use,
      loader: 'esbuild-loader',
      options,
    }
  }

I highly discourage anyone to use example above in real projects. You should find a better and more reliable way to maintain your webpack config.
I was really amazed by how built time reduced, tho.

@gianpaj
Copy link

gianpaj commented Aug 11, 2023

I can't make this work with Next 13

TypeError: Cannot read properties of undefined (reading 'useSourceMap')
    at /next/node_modules/.pnpm/esbuild-loader@4.0.0_webpack@5.88.2/node_modules/esbuild-loader/dist/index.cjs:192:40
    at _next3 (eval at create (/next/node_modules/.pnpm/next@13.4.12_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0_sass@1.64.2/node_modules/next/dist/compiled/webpack/bundle5.js:13:28867), <anonymous>:19:1)
    at eval (eval at create (/next/node_modules/.pnpm/next@13.4.12_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0_sass@1.64.2/node_modules/next/dist/compiled/webpack/bundle5.js:13:28867), <anonymous>:54:1)
"esbuild-loader": "^4.0.0",
"next": "^13.4.12",
"typescript": "^4.9.5",
"webpack": "^5.88.2"

next.config.js

/* eslint-disable @typescript-eslint/no-var-requires */

const { EsbuildPlugin } = require("esbuild-loader");

function esbuildMinify(config, options) {
  const { minimizer } = config.optimization;
  const terserIndex = minimizer.findIndex((minifier) => minifier.constructor.name === "TerserPlugin");

  minimizer.splice(terserIndex, 1, new EsbuildPlugin(options));
}

function esbuildLoader(config, options) {
  const { rules } = config.module;
  const rule = rules.find((rule) => rule.test?.test(".js"));

  if (rule) {
    rule.use = {
      ...rule.use,
      loader: "esbuild-loader",
      options,
    };
  }
}

const path = require("path");
const withPurgeCSSModules = require("next-purge-css-modules");

/**
 * @type {import('next').NextConfig}
 **/
const nextConfig = {
  reactStrictMode: true,
  compress: true,
  images: {
    unoptimized: true,
  },
  exportPathMap: function () {
    return {
    };
  },
  purgeCSSModules: {
    content: path.join(__dirname, "src/**/*.{js,jsx,ts,tsx}"),
  },
  experimental: {
    optimizeCss: true,
  },
  modularizeImports: {
    "@mui/icons-material": {
      transform: "@mui/icons-material/{{member}}",
    },
  },
  webpack: (config, { webpack }) => {
    config.plugins.push(
      new webpack.ProvidePlugin({
        React: "react",
      })
    );

    esbuildMinify(config);
    esbuildLoader(config, {
      loader: "tsx",
      target: "esnext",
    });

    Object.assign(config.resolve.alias, {
      react: "preact/compat",
      "react-dom/test-utils": "preact/test-utils",
      "react-dom": "preact/compat",
    });
    return config;
  },
};

const withBundleAnalyzer = require("@next/bundle-analyzer")({
  enabled: process.env.ANALYZE === "true",
});
module.exports = () => {
  return withBundleAnalyzer(withPurgeCSSModules(nextConfig));
};

@privatenumber
Copy link
Owner

This issue was closed 3 years ago. If you need help, please ask a question in Discussions or Next.js's repo.

Repository owner locked as resolved and limited conversation to collaborators Aug 12, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
help wanted Extra attention is needed question Further information is requested
Projects
None yet
Development

No branches or pull requests

10 participants