material-ui icon indicating copy to clipboard operation
material-ui copied to clipboard

Using Next.js 13, some imports (particularly SxProps type) are causing TypeScript and `next build` to stall

Open brandonscript opened this issue 2 years ago • 7 comments

Duplicates

  • [X] I have searched the existing issues

Latest version

  • [X] I have tested the latest version

Steps to reproduce 🕹

Link to live example: (N/A)

Steps:

  1. use npx create-next-app to build a Next.js 13 project with TypeScript=yes, ESLint=yes, experimental app dir=yes
  2. Create a new file (
  3. in my case this is an icon file) that imports { SxProps} from @mui/material (see below code example):
  4. Run next build from terminal, and it will stall out on "Linting and checking validity of types". TypeScript in VSCode will also churn for a very long time or indefinitely, possibly because of some circular imports? A Shift ⌘ P Restart TypeScript Server sometimes fixes it.
  5. Possibly related: https://github.com/vercel/next.js/issues/32314 - I have tried the experimental disable esm option (Next seems to not care), and the other transpilePackages option (which Next doesn't even seem to recognize on 13 anymore?) to no avail.

In short, it seems that SxProps is maybe importing from the wrong place, or creating a circular import. If I copy out the type definition for SxProps, and instead try importing SystemStyleObject, it tries to import it from @mui/system which doesn't seem to be there:

import { SystemStyleObject } from "@mui/system";
  
type SxProps<Theme extends object = {}> =
  | SystemStyleObject<Theme>
  | ((theme: Theme) => SystemStyleObject<Theme>)
  | ReadonlyArray<
      boolean | SystemStyleObject<Theme> | ((theme: Theme) => SystemStyleObject<Theme>)
    >;

But replacing any reference to SystemStyleObject<Theme> with any allows the project to build. If I continue down this rabbit hole, it seems like any types imported from @mui/system/styleFunctionSx causes this problem.

Current behavior 😯

Screenshot 2023-02-03 at 9 27 50 AM

Terminal just does this indefinitely, have to force kill it. It also stalls out in the Next -> Vercel deployment, and there are no build logs anywhere that I can see.

Expected behavior 🤔

It is maybe too much to ask, but

info  - Generating static pages (3/3)
info  - Finalizing page optimization  

Route (app)                                Size     First Load JS
─ ○ /                                      0 B                0 B
+ First Load JS shared by all              82.7 kB
  ├ chunks/17-f2d707dd60cbbe95.js          80.4 kB
  ├ chunks/main-app-75838474ac2d918f.js    216 B
  └ chunks/webpack-bf40d3e2e2b9f54b.js     2.11 kB

Route (pages)                              Size     First Load JS
┌ ○ /404                                   179 B          81.2 kB
├ λ /api/hello                             0 B              81 kB
+ First Load JS shared by all              81 kB
  ├ chunks/main-7f0563c831689cf4.js        78.7 kB
  ├ chunks/pages/_app-5841ab2cb3aa228d.js  192 B
  └ chunks/webpack-bf40d3e2e2b9f54b.js     2.11 kB

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)
○  (Static)  automatically rendered as static HTML (uses no initial props)

✨  Done in 10.87s.

Context 🔦

Not how this is affecting me, but project structure may help:

(This is a standard Next wizard built app, but nevertheless)

.next/
.vscode/
public/
src/
  ﹂app/
      lib/
      pages/api/hello.ts // stock, no changes
      styles/
        ﹂colors/
             ﹂colors.types.ts
        ﹂icons/
             ﹂AircraftPrivateJetMd.tsx
           appTheme.ts
// generated via: https://github.com/brandonscript/mui-svg-icons-generator
import * as React from "react";
import { CSSProperties } from "@mui/styles";
import { SvgIcon, SvgIconProps, SxProps } from "@mui/material";
//                                 ^ the sadness
// import type { SxProps } from "@mui/system/styleFunctionSx/styleFunctionSx.d";
// ^ have had some success importing from here - I got it to compile just twice, but VSCode doesn't seem to know about this path, and it has failed every other time.
import { memo } from "react";
const SvgAircraftPrivateJetMd = (
  props: SvgIconProps & { sx?: SxProps<CSSProperties> }
) => {
  const { sx, ...other } = props;

  const fontSize =
    other.fontSize || sx?.fontSize || other?.style?.fontSize || undefined;
  const sizeClassName = fontSize
    ? "PacificAviatorSvgIcon-sizeCustom"
    : "PacificAviatorSvgIcon-sizeMd";
  return (
    <SvgIcon
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      preserveAspectRatio="xMidYMid meet"
      viewBox="0 0 30 30"
      className={`PacificAviatorSvgIcon-AircraftPrivateJetIcon_md ${sizeClassName}`}
      style={{
        fill: "none",
      }}
      sx={{
        ...sx,
      }}
      {...other}
    >
      <path
        d="M10.1 17.212a4.9 4.9 0 1 0 9.8 0 4.9 4.9 0 0 0-9.8 0ZM13.367 15.58h3.266M15 12.313V7.888M11.235 14.078 9.078 11.92M6.29 10.766a1.633 1.633 0 1 0 3.266 0 1.633 1.633 0 0 0-3.266 0ZM18.765 14.078l2.157-2.157M20.444 10.766a1.633 1.633 0 1 0 3.266 0 1.633 1.633 0 0 0-3.266 0Z"
        stroke="currentColor"
        strokeWidth={1.503}
        strokeLinecap="round"
        strokeLinejoin="round"
      />
      <path
        d="M18.163 20.953h6.908a2.178 2.178 0 0 0 2.178-2.177M2.751 18.776a2.177 2.177 0 0 0 2.178 2.177h6.913M12.822 7.888h4.356"
        stroke="currentColor"
        strokeWidth={1.503}
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </SvgIcon>
  );
};
const Memo = memo(SvgAircraftPrivateJetMd);
export default Memo;
// appTheme.ts

import { createTheme, responsiveFontSizes, Theme } from "@mui/material/styles";

const theme: Theme = createTheme({
  palette: {
    mode: "light",
  },
  components: {
      // none
  },
});

const compositeTheme = responsiveFontSizes((theme), {
  factor: 1.25,
});

export default compositeTheme;
// colors.types.ts

import { Palette, PaletteOptions } from "@mui/material";

export interface ExtendedPalette<T extends Palette | PaletteOptions> {
  brand?: T["primary"];
}

declare module "@mui/material/styles/createPalette" {
  interface TypeBackground {
    well?: string;
  }
}

declare module "@mui/material/styles" {
  interface Palette extends ExtendedPalette<Palette> {}
  interface PaletteOptions extends ExtendedPalette<PaletteOptions> {}
}
// tsconfig.json

{
  "compilerOptions": {
    "baseUrl": "./src",
    "target": "ESNext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}
// next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    appDir: true,
  },
  eslint: {
    ignoreDuringBuilds: true,
  },
};

module.exports = nextConfig
// package.json

{
  "name": "next13-test",
  "version": "2.0.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@emotion/react": "^11.10.5",
    "@emotion/styled": "^11.10.5",
    "@mui/material": "^5.11.7",
    "@mui/styled-engine": "^5.11.0",
    "@mui/styles": "^5.11.7",
    "@mui/system": "^5.11.7",
    "@next/font": "^13.1.6",
    "@types/node": "18.11.18",
    "@types/react": "18.0.26",
    "@types/react-dom": "18.0.10",
    "eslint": "8.30.0",
    "eslint-config-next": "^13.1.6",
    "next": "^13.1.6",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "main": "app/page.tsx",
  "devDependencies": {
    "@babel/core": "^7.0.0",
    "@types/react-syntax-highlighter": "^15.5.5",
    "prettier": "^2.8.3",
    "typescript": "^4.9.5",
    "yarn": "^1.22.19"
  }
}

Your environment 🌎

npx @mui/envinfo
  npx: installed 2 in 1.512s

  System:
    OS: macOS 13.1
  Binaries:
    Node: 18.3.0 - ~/.local/share/nvm/v18.3.0/bin/node
    Yarn: 1.22.19 - ~/Dev/next13-test/node_modules/.bin/yarn
    npm: 8.11.0 - ~/.local/share/nvm/v18.3.0/bin/npm
  Browsers:
    Chrome: 109.0.5414.119 <- normally I use for dev, but this is a headless problem.
    Edge: Not Found
    Firefox: 107.0
    Safari: 16.2
  npmPackages:
    @emotion/react: ^11.10.5 => 11.10.5 
    @emotion/styled: ^11.10.5 => 11.10.5 
    @mui/base:  5.0.0-alpha.116 
    @mui/core-downloads-tracker:  5.11.7 
    @mui/material: ^5.11.7 => 5.11.7 
    @mui/private-theming:  5.11.7 
    @mui/styled-engine: ^5.11.0 => 5.11.0 
    @mui/styles: ^5.11.7 => 5.11.7 
    @mui/system: ^5.11.7 => 5.11.7 
    @mui/types:  7.2.3 
    @mui/utils:  5.11.7 
    @types/react: 18.0.26 => 18.0.26 
    react: ^18.2.0 => 18.2.0 
    react-dom: ^18.2.0 => 18.2.0 
    typescript: ^4.9.5 => 4.9.5 

brandonscript avatar Feb 03 '23 17:02 brandonscript

Being struggling with the same error for days. I believe in my case it's related to the Autocomplete component

pcriadoperez avatar Feb 07 '23 12:02 pcriadoperez

@brandonscript can you please create github repository that I can clone and test this out? I want to make sure that everything is set up exactly as in your repository.

mnajdova avatar Feb 07 '23 12:02 mnajdova

@mnajdova hey Marija, sorry this took so long – a juggling a few things right now. Here you go: https://github.com/brandonscript/next13-mui-system-typescript-bug

brandonscript avatar Feb 08 '23 17:02 brandonscript

Probably I've caught a similar issue when building lib with NX(vite). When I've added: type MyCmpProps = { sx?: SxProps<Theme>; ... } It has caused the "Start generate declaration files..." step takes forever.

After some diving in I've found the reason is: "type SystemStyleObject"

It's not a genuinely proper fix but it works for me as for now:

  • I've made a dirty fixed clone of "SystemStyleObject" and "SxProps". And used it where I need it.
import {CSSPseudoSelectorProps, CSSSelectorObjectOrCssVariables, SystemCssProperties} from "@mui/system/styleFunctionSx/styleFunctionSx";

export type SystemStyleObject<Theme extends object = {}> =
  | SystemCssProperties<Theme>
  | CSSPseudoSelectorProps<Theme>
  | CSSSelectorObjectOrCssVariables<Theme>
  | any // <---dirty hotfix
  | null;

export type SxProps<Theme extends object = {}> =
  | SystemStyleObject<Theme>
  | ((theme: Theme) => SystemStyleObject<Theme>)
  | ReadonlyArray<
  boolean | SystemStyleObject<Theme> | ((theme: Theme) => SystemStyleObject<Theme>)
>;

nikita-yaroshevich avatar Apr 16 '23 23:04 nikita-yaroshevich

@brandonscript Have you tried adding 'use client'; at the beginning of the files which are using mui?

nikelborm avatar May 01 '23 14:05 nikelborm

@nikelborm sure did. I split it out into server components with nested client components.

brandonscript avatar May 01 '23 14:05 brandonscript

I have the same issue but within a React (Vite) project: importing SxProps causes tsc to stall. My IDE self-imports it from '@mui/material' though (not from "@mui/system/styleFunctionSx"), but both options are causing the stall.

Also: if I pass to SxProps the optional generic, it doesn't stall anymore! [EDIT] the last sentence is incorrect. It didn't stall because I was passing a wrong generic causing a type signature mismatch. So if it fails, it doesn't stall [/EDIT]

Any clues?

xela92 avatar May 04 '23 13:05 xela92

you can use as a "reference" to existing "sx" property, for example:

import Button, { ButtonProps } from '@mui/material/Button'

const a: ButtonProps['sx'] = {}

This will solve it

d0whc3r avatar May 10 '23 11:05 d0whc3r

you can use as a "reference" to existing "sx" property, for example:

import Button, { ButtonProps } from '@mui/material/Button'

const a: ButtonProps['sx'] = {}

This will solve it

As a workaround it worked fine for me, thanks! 👍

xela92 avatar May 15 '23 09:05 xela92

@d0whc3r we were having a similar issue with a CRA with Typescript project using MUI v6!!

You helped us pin the same issue we were experiencing when executing react-scripts build: importing SxProps directly from import { SxProps } from '@mui/system'; or even import { SxProps } from '@mui/materials/styles'; resulted in a memory leak!

The solution was to import sx's type directly from the MUI component, for instance SelectProps['sx'], ButtonProps['sx'] etc.... 😅

I hope MUI can fix the way they export their types...

Audrey-Ann avatar May 24 '23 20:05 Audrey-Ann