aidenybai / million

Optimize React performance and make your React 70% faster in minutes, not months.
https://million.dev
MIT License
15.94k stars 559 forks source link

`million/compiler` failed to check nextjs `app` dir inside `src` dir #958

Open 0x221A opened 5 months ago

0x221A commented 5 months ago

What version of million are you using?

3.0.3

Are you using an SSR adapter? If so, which one?

None

What package manager are you using?

pnpm

What operating system are you using?

Mac

What browser are you using?

Chrome

Describe the Bug

million/compiler failed to auto-determine whether the user is using app dir inside src dir. This caused the compiler to fail to compile RSC.

https://github.com/aidenybai/million/blob/ec34eba56d9640b2a57d3ab4fd5246bdc94db5cd/packages/compiler/index.ts#L35

What's the expected result?

The compiler should correctly determine whether the user is using app dir inside src dir or not.

Workaround

Manually set CompilerOptions.rsc to true.

export default million.next(nextConfig, { auto: { rsc: true }, rsc: true });

Link to Minimal Reproducible Example

https://stackblitz.com/edit/stackblitz-starters-vmkrup

Participation

github-actions[bot] commented 5 months ago

Thanks for opening this issue! A maintainer will review it soon.

SalahAdDin commented 5 months ago

I thought it was happening only for either localized or multi plugin projects cause:

/** @type {import('next').NextConfig} */

import createNextIntlPlugin from "next-intl/plugin";
import million from "million/compiler";

const withNextIntl = createNextIntlPlugin();

const millionConfig = {
  auto: true,
};

const nextConfig = {
  experimental: {
    instrumentationHook: true,
  },
  webpack(config, { isServer }) {
   if (isServer) {
      if (Array.isArray(config.resolve.alias)) {
        config.resolve.alias.push({ name: "msw/browser", alias: false });
      } else {
        config.resolve.alias["msw/browser"] = false;
      }
    } else {
      if (Array.isArray(config.resolve.alias)) {
        config.resolve.alias.push({ name: "msw/node", alias: false });
      } else {
        config.resolve.alias["msw/node"] = false;
      }
    }
    return config;
  },
  productionBrowserSourceMaps: true,
  reactStrictMode: true,
};

export default million.next(withNextIntl(nextConfig, millionConfig));

It was failing on loading.

After applying the workaround, running dev does fail anymore, even if we use auto: true, i.e., we don't use the workaround.

It is very weird.

0x221A commented 5 months ago

@SalahAdDin I don't think that is the correct way to use the million.next function. To override the million config and use the custom plugin you should chain the plugin like this:

export default million.next(withNextIntl(nextConfig), millionConfig);

You don't need to use this workaround if your project doesn't use RSC. The workaround only useful for the project that using app dir and it's living inside src dir.

SalahAdDin commented 5 months ago

@SalahAdDin I don't think that is the correct way to use the million.next function. To override the million config and use the custom plugin you should chain the plugin like this:

export default million.next(withNextIntl(nextConfig), millionConfig);

You don't need to use this workaround if your project doesn't use RSC. The workaround only useful for the project that using app dir and it's living inside src dir.

Well, You made me the key to remember the issue:

 pnpm dev                                                         ✔  20.11.0  

> global-web-fe@0.1.0 dev /home/luisalaguna/Projects/TRT/twe_fe_next
> next dev

   ▲ Next.js 14.1.0
   - Local:        http://localhost:3000
   - Experiments (use at your own risk):
     · instrumentationHook

 ✓ Ready in 2.3s
 ⚠ Found a change in next.config.mjs. Restarting the server to apply the changes...
   ▲ Next.js 14.1.0
   - Local:        http://localhost:3000
   - Experiments (use at your own risk):
     · instrumentationHook

 ✓ Ready in 2.1s
 ✓ Compiled /src/middleware in 314ms (86 modules)

  ⚡ Million.js 3.0.3
  - Tip:     use // million-ignore for errors
  - Hotline: https://million.dev/hotline

 ○ Compiling /[locale] ...
 ✓ Compiled /[locale] in 4s (1060 modules)
 ⨯ node_modules/.pnpm/@radix-ui+react-direction@1.0.1_@types+react@18.2.55_react@18.2.0/node_modules/@radix-ui/react-direction/dist/index.mjs (4:82) @ undefined
 ⨯ TypeError: (0 , react__WEBPACK_IMPORTED_MODULE_0__.createContext) is not a function
    at eval (webpack-internal:///(rsc)/./node_modules/.pnpm/@radix-ui+react-direction@1.0.1_@types+react@18.2.55_react@18.2.0/node_modules/@radix-ui/react-direction/dist/index.mjs:9:114)
    at (rsc)/./node_modules/.pnpm/@radix-ui+react-direction@1.0.1_@types+react@18.2.55_react@18.2.0/node_modules/@radix-ui/react-direction/dist/index.mjs (/home/luisalaguna/Projects/TRT/twe_fe_next/.next/server/vendor-chunks/@radix-ui+react-direction@1.0.1_@types+react@18.2.55_react@18.2.0.js:20:1)
    at __webpack_require__ (/home/luisalaguna/Projects/TRT/twe_fe_next/.next/server/webpack-runtime.js:33:42)
    at eval (webpack-internal:///(rsc)/./src/app/[locale]/layout.tsx:11:83)
    at (rsc)/./src/app/[locale]/layout.tsx (/home/luisalaguna/Projects/TRT/twe_fe_next/.next/server/app/[locale]/page.js:237:1)
    at Function.__webpack_require__ (/home/luisalaguna/Projects/TRT/twe_fe_next/.next/server/webpack-runtime.js:33:42)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async collectGenerateParams (/home/luisalaguna/Projects/TRT/twe_fe_next/node_modules/.pnpm/next@14.1.0_@babel+core@7.23.9_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/utils.js:919:21)
    at async Object.loadStaticPaths (/home/luisalaguna/Projects/TRT/twe_fe_next/node_modules/.pnpm/next@14.1.0_@babel+core@7.23.9_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/static-paths-worker.js:46:13) {
  type: 'TypeError',
  page: '/en'
}
null
 ○ Compiling /_error ...
 ✓ Compiled /_error in 3.5s (1167 modules)

It happens when we use export default million.next(withNextIntl(nextConfig), millionConfig); and const millionConfig = { auto: true,};!!!

When we use const millionConfig = { auto: { rsc: true }, }; it still happens.

So, it is not a workaround in this case.

Workaround

Our solution is export default million.next(withNextIntl(nextConfig, millionConfig));.

Update:

Now, it does not work, again!

0x221A commented 5 months ago

@SalahAdDin As I said in the workaround you need to manually set CompilerOptions.rsc to true. So your config should be something like this.

export default million.next(withNextIntl(nextConfig), { auto: { rsc: true }, rsc: true });

millionConfig is the object that passes to override the default config of million.next. It doesn't do anything if you chain it to nextConfig.

SalahAdDin commented 5 months ago
export default million.next(withNextIntl(nextConfig), { auto: { rsc: true }, rsc: true });

Not working for me:

- Experiments (use at your own risk):
      · auto-rsc

 ✓ Compiled /[locale] in 6.9s (1051 modules)
 ⨯ node_modules/.pnpm/@radix-ui+react-direction@1.0.1_@types+react@18.2.55_react@18.2.0/node_modules/@radix-ui/react-direction/dist/index.mjs (4:82) @ undefined
 ⨯ TypeError: (0 , react__WEBPACK_IMPORTED_MODULE_0__.createContext) is not a function
    at eval (webpack-internal:///(rsc)/./node_modules/.pnpm/@radix-ui+react-direction@1.0.1_@types+react@18.2.55_react@18.2.0/node_modules/@radix-ui/react-direction/dist/index.mjs:9:114)
    at (rsc)/./node_modules/.pnpm/@radix-ui+react-direction@1.0.1_@types+react@18.2.55_react@18.2.0/node_modules/@radix-ui/react-direction/dist/index.mjs (/home/luisalaguna/Projects/TRT/twe_fe_next/.next/server/vendor-chunks/@radix-ui+react-direction@1.0.1_@types+react@18.2.55_react@18.2.0.js:20:1)
    at __webpack_require__ (/home/luisalaguna/Projects/TRT/twe_fe_next/.next/server/webpack-runtime.js:33:42)
    at eval (webpack-internal:///(rsc)/./src/app/[locale]/layout.tsx:10:83)
    at (rsc)/./src/app/[locale]/layout.tsx (/home/luisalaguna/Projects/TRT/twe_fe_next/.next/server/app/[locale]/page.js:237:1)
    at Function.__webpack_require__ (/home/luisalaguna/Projects/TRT/twe_fe_next/.next/server/webpack-runtime.js:33:42)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async collectGenerateParams (/home/luisalaguna/Projects/TRT/twe_fe_next/node_modules/.pnpm/next@14.1.0_@babel+core@7.23.9_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/utils.js:919:21)
    at async Object.loadStaticPaths (/home/luisalaguna/Projects/TRT/twe_fe_next/node_modules/.pnpm/next@14.1.0_@babel+core@7.23.9_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/static-paths-worker.js:46:13) {
  type: 'TypeError',
  page: '/en'
}
null
 ○ Compiling /_error ...
 ✓ Compiled /_error in 2.3s (1158 modules)
 ⨯ node_modules/.pnpm/@radix-ui+react-direction@1.0.1_@types+react@18.2.55_react@18.2.0/node_modules/@radix-ui/react-direction/dist/index.mjs (4:82) @ undefined
 ⨯ TypeError: (0 , react__WEBPACK_IMPORTED_MODULE_0__.createContext) is not a function
    at eval (webpack-internal:///(rsc)/./node_modules/.pnpm/@radix-ui+react-direction@1.0.1_@types+react@18.2.55_react@18.2.0/node_modules/@radix-ui/react-direction/dist/index.mjs:9:114)
    at (rsc)/./node_modules/.pnpm/@radix-ui+react-direction@1.0.1_@types+react@18.2.55_react@18.2.0/node_modules/@radix-ui/react-direction/dist/index.mjs (/home/luisalaguna/Projects/TRT/twe_fe_next/.next/server/vendor-chunks/@radix-ui+react-direction@1.0.1_@types+react@18.2.55_react@18.2.0.js:20:1)
    at __webpack_require__ (/home/luisalaguna/Projects/TRT/twe_fe_next/.next/server/webpack-runtime.js:33:42)
    at eval (webpack-internal:///(rsc)/./src/app/[locale]/layout.tsx:10:83)
    at (rsc)/./src/app/[locale]/layout.tsx (/home/luisalaguna/Projects/TRT/twe_fe_next/.next/server/app/[locale]/page.js:237:1)
    at Function.__webpack_require__ (/home/luisalaguna/Projects/TRT/twe_fe_next/.next/server/webpack-runtime.js:33:42)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async collectGenerateParams (/home/luisalaguna/Projects/TRT/twe_fe_next/node_modules/.pnpm/next@14.1.0_@babel+core@7.23.9_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/utils.js:919:21)
    at async Object.loadStaticPaths (/home/luisalaguna/Projects/TRT/twe_fe_next/node_modules/.pnpm/next@14.1.0_@babel+core@7.23.9_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/static-paths-worker.js:46:13) {
  type: 'TypeError',
  page: '/en'
}
null
0x221A commented 5 months ago

@SalahAdDin Then I think it's not related to the issue. From the error, it seems like you're using DirectionProvider directly in the server component without re-export it from @radix-ui/react-direction. As the error said createContext is not a function which means the compiler thinks that component is a server component. If you want to use a third-party react ui component such as radix-ui you need to re-export it with "use client" directive.

SalahAdDin commented 5 months ago

@SalahAdDin As I said in the workaround you need to manually set CompilerOptions.rsc to true. So your config should be something like this.

export default million.next(withNextIntl(nextConfig), { auto: { rsc: true }, rsc: true });

millionConfig is the object that passes to override the default config of million.next. It doesn't do anything if you chain it to nextConfig.

Well, it is working well after removing the provider.

In your opinion this workaround should not be required, right?

Thank you!

0x221A commented 5 months ago

@SalahAdDin The workaround is required if you're using app directory inside src directory as I said at first.

SalahAdDin commented 4 months ago

@SalahAdDin The workaround is required if you're using app directory inside src directory as I said at first.

But it should be working without the workaround, right?

github-actions[bot] commented 4 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs within the next 7 days.

SalahAdDin commented 4 months ago

@aidenybai any news on this issue?

nikshepsvn commented 3 months ago

bump here, same issue -- anyone got around this?

IamSoPrada commented 3 months ago

bump

Lucasvo1 commented 3 months ago

Workaround doesn't work for me on Nextjs 14 with app dir inside src.

0x221A commented 3 months ago

Workaround doesn't work for me on Nextjs 14 with app dir inside src.

Can I see the config?

Lucasvo1 commented 3 months ago
await import("./src/env.js");
import bundleAnalyzer from "@next/bundle-analyzer";
import million from "million/compiler";

const withBundleAnalyzer = bundleAnalyzer({
  enabled: process.env.ANALYZE === "true",
});

/** @type {import('next').NextConfig} */
const nextConfig = {
 reactStrictMode: true,
 i18n: {
   locales: ["en", "fr", "nl", "pt"],
   defaultLocale: "en",
 },
};

/* const millionConfig = {
 auto: true,
};
export default million.next(withBundleAnalyzer(nextConfig), millionConfig); */

export default million.next(withBundleAnalyzer(nextConfig), {
  auto: { rsc: true },
  rsc: true,
 });

I think it actually has to do with the type of NextConfig being passed to million.next.

Argument of type 'NextConfig' is not assignable to parameter of type '{ appDir?: boolean | undefined; basePath?: string | undefined; webpack?: ((config: Record<string, any>, options: any) => any) | undefined; }'.
 Types of property 'webpack' are incompatible.
   Type 'NextJsWebpackConfig | null | undefined' is not assignable to type '((config: Record<string, any>, options: any) => any) | undefined'.
     Type 'null' is not assignable to type '((config: Record<string, any>, options: any) => any) | undefined'.ts(2345)
IamSoPrada commented 3 months ago

My project also has several plugins and uses src/app/[locale] structure. For me reason of my problems was 'next-compose-plugins'.

I tried to pass it like that :

export default million.next(withPlugins([withPWA, withBundleAnalyzer, withNextIntlConfig], nextConfig), {
  auto: { rsc: true },
  rsc: true,
});

as soon as i changed it to this it started working:

export default million.next(withBundleAnalyzer(withPWA(withNextIntlConfig(nextConfig))), {
  auto: { rsc: true },
  rsc: true,
});

My next.config.mjs :

import withNextIntl from 'next-intl/plugin'
//import withPlugins from 'next-compose-plugins'
import bundleAnalyzer from '@next/bundle-analyzer'
import withPWAInit from '@ducanh2912/next-pwa';
import million from "million/compiler";

const withNextIntlConfig = withNextIntl('./src/libs/i18n.ts');
const withBundleAnalyzer = bundleAnalyzer({
  enabled: process.env.ANALYZE === 'true',
});

const withPWA = withPWAInit({
  dest: 'public',
  cacheOnFrontEndNav: true,
  aggressiveFrontEndNavCaching: true,
  reloadOnOnline: true,
  disable: false,
  workboxOptions: {
    disableDevLogs: true,
    maximumFileSizeToCacheInBytes: 250000
  }
  /*register: true,
  skipWaiting: true*/
})

const nextConfig = {
  //output: 'standalone',
  //distDir: 'build',
  productionBrowserSourceMaps: true,
  async headers() {
    const headers = [];

    headers.push({
      source: '/:all*(svg|jpg|jpeg|png|gif|ico|webp)',
      locale: false,
      headers: [
        {
          key: 'Cache-Control',
          value: 'public, max-age=31536000, stale-while-revalidate',
        },
      ],
    });

    // Prevent search engines from indexing the site if it is not live
    // This is useful for staging environments before they are ready to go live
    headers.push({
      headers: [
        {
          key: 'X-Robots-Tag',
          value: 'noindex',
        },
      ],
      source: '/:path*',
    });

    return headers;
  },

  webpack(config, {isServer}) {
    config.module.rules.push({
      test: /\.svg$/i,
      issuer: /\.[jt]sx?$/,
      use: ['@svgr/webpack'],
    });

    config.externals.push({
      bufferutil: 'bufferutil',
      'utf-8-validate': 'utf-8-validate',
    });

    if (isServer) {
      if (Array.isArray(config.resolve.alias)) {
        config.resolve.alias.push({ name: "msw/browser", alias: false });
      } else {
        config.resolve.alias["msw/browser"] = false;
      }
    } else {
      if (Array.isArray(config.resolve.alias)) {
        config.resolve.alias.push({ name: "msw/node", alias: false });
      } else {
        config.resolve.alias["msw/node"] = false;
      }
    }

    return config;
  },
  images: {
    deviceSizes: [320, 428, 744, 1024, 1440, 1920, 2048],
    formats: ['image/avif', 'image/webp'],
    domains: [
      'localhost',
      process.env.NEXT_PUBLIC_API_URL,
    ]
      .filter(Boolean)
      .map(url => url.replace(/https?:\/\//, '')),

  },
};

/** @type {import('next').NextConfig} */

//withPlugins([withPWA, withBundleAnalyzer, withNextIntlConfig,], nextConfig)

export default million.next(withBundleAnalyzer(withPWA(withNextIntlConfig(nextConfig))), {
  auto: { rsc: true },
  rsc: true,
});
github-actions[bot] commented 3 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs within the next 7 days.

github-actions[bot] commented 2 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs within the next 7 days.

SalahAdDin commented 2 months ago

Up!

tobySolutions commented 2 months ago

Are you still experiencing this issue @SalahAdDin? It should have been fixed by now.

SalahAdDin commented 2 months ago

Are you still experiencing this issue @SalahAdDin? It should have been fixed by now.

Is there any new release? I can't see it here.

0x221A commented 2 months ago

@SalahAdDin With the latest release of next.js and million.js, it seems like this has not been fixed yet.

advanceddev commented 2 months ago

Same issue

github-actions[bot] commented 2 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs within the next 7 days.

SalahAdDin commented 1 month ago

Are you still experiencing this issue @SalahAdDin? It should have been fixed by now.

Yeah, we are still experiencing the issue.

x86developers commented 1 month ago

agreed with @IamSoPrada

I could only get it work this way with the latest version of nextjs "next": "14.2.3",

image
import bundleAnalyzer from "@next/bundle-analyzer";
import million from "million/compiler";
import MillionLint from "@million/lint";

const withBundleAnalyzer = bundleAnalyzer({
  enabled: process.env.ANALYZE === "true",
});

const nextConfig = {
  productionBrowserSourceMaps: true,
  async headers() {
    const headers = [];
    headers.push({
      source: "/:all*(svg|jpg|jpeg|png|gif|ico|webp)",
      locale: false,
      headers: [
        {
          key: "Cache-Control",
          value: "public, max-age=31536000, stale-while-revalidate",
        },
      ],
    });
    headers.push({
      headers: [
        {
          key: "X-Robots-Tag",
          value: "noindex",
        },
      ],
      source: "/:path*",
    });
    return headers;
  },
  webpack(config, { isServer }) {
    config.module.rules.push({
      test: /\.svg$/i,
      issuer: /\.[jt]sx?$/,
      use: ["@svgr/webpack"],
    });
    config.externals.push({
      bufferutil: "bufferutil",
      "utf-8-validate": "utf-8-validate",
    });
    if (isServer) {
      if (Array.isArray(config.resolve.alias)) {
        config.resolve.alias.push({ name: "msw/browser", alias: false });
      } else {
        config.resolve.alias["msw/browser"] = false;
      }
    } else {
      if (Array.isArray(config.resolve.alias)) {
        config.resolve.alias.push({ name: "msw/node", alias: false });
      } else {
        config.resolve.alias["msw/node"] = false;
      }
    }
    return config;
  },
  images: {
    deviceSizes: [320, 428, 744, 1024, 1440, 1920, 2048],
    formats: ["image/avif", "image/webp"],
    remotePatterns: [
      {
        protocol: "http",
        hostname: "localhost",
      },
    ],
  },
};

export default million.next(withBundleAnalyzer(nextConfig), {
  auto: { rsc: true },
  rsc: true,
});

With out this I get this error

Module not found: Can't resolve '/myproject/src/app/dashboard/layout.tsx' Module not found: Can't resolve '/myproject/src/app/layout.tsx'

https://nextjs.org/docs/messages/module-not-found

ugursepetci commented 1 month ago

same issue

Screenshot 2024-05-31 at 15 36 52