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

Material UI breaks Remix SPA build (but works fine in regular Remix apps) #9632

Closed
npapagna opened this issue Jun 18, 2024 · 6 comments
Closed

Comments

@npapagna
Copy link
Contributor

npapagna commented Jun 18, 2024

Reproduction

Clone https://github.com/npapagna/remix_spa_mui_repro and follow steps to reproduce described in the README.md file.

System Info

System:
    OS: macOS 13.6.6
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 4.37 GB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.11.1 - ~/.nvm/versions/node/v20.11.1/bin/node
    Yarn: 1.22.19 - ~/.nvm/versions/node/v18.16.0/bin/yarn
    npm: 10.2.4 - ~/.nvm/versions/node/v20.11.1/bin/npm
    pnpm: 8.14.0 - /usr/local/bin/pnpm
  Browsers:
    Brave Browser: 124.1.65.126
    Chrome: 126.0.6478.61
    Safari: 16.6
  npmPackages:
    @remix-run/dev: ^2.9.2 => 2.9.2 
    @remix-run/node: ^2.9.2 => 2.9.2 
    @remix-run/react: ^2.9.2 => 2.9.2 
    vite: ^5.1.0 => 5.3.1

Used Package Manager

npm

Expected Behavior

I was expecting npm run build to finish successfully.

Actual Behavior

Running npm run build fails with the following error:

> build
> remix vite:build

vite v5.3.1 building for production...
transforming...
✓ 1149 modules transformed.
x Build failed in 2.52s
app/root.tsx (10:7): "default" is not exported by "node_modules/@mui/material/locale/index.js", imported by "app/root.tsx".
file: /Users/nicopm/WebstormProjects/remix_spa_mui_repro/app/root.tsx:10:7

 8: import "./tailwind.css";
 9: import {createTheme, CssBaseline, ThemeProvider} from "@mui/material";
10: import pkg from '@mui/material/locale/index.js';
           ^
11: const { esES } = pkg;

    at getRollupError (file:https:///Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/rollup/dist/es/shared/parseAst.js:396:41)
    at error (file:https:///Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/rollup/dist/es/shared/parseAst.js:392:42)
    at Module.error (file:https:///Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/rollup/dist/es/shared/node-entry.js:13858:16)
    at Module.traceVariable (file:https:///Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/rollup/dist/es/shared/node-entry.js:14306:29)
    at ModuleScope.findVariable (file:https:///Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/rollup/dist/es/shared/node-entry.js:11984:39)
    at Identifier.bind (file:https:///Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/rollup/dist/es/shared/node-entry.js:6908:40)
    at VariableDeclarator.bind (file:https:///Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/rollup/dist/es/shared/node-entry.js:4775:23)
    at VariableDeclaration.bind (file:https:///Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/rollup/dist/es/shared/node-entry.js:4771:28)
    at Program.bind (file:https:///Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/rollup/dist/es/shared/node-entry.js:4771:28)
    at Module.bindReferences (file:https:///Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/rollup/dist/es/shared/node-entry.js:13839:18) {
  binding: 'default',
  code: 'MISSING_EXPORT',
  exporter: '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/locale/index.js',
  id: '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/app/root.tsx',
  url: 'https://rollupjs.org/troubleshooting/#error-name-is-not-exported-by-module',
  pos: 236,
  loc: {
    column: 7,
    file: '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/app/root.tsx',
    line: 10
  },
  frame: ' 8: import "./tailwind.css";\n' +
    ' 9: import {createTheme, CssBaseline, ThemeProvider} from "@mui/material";\n' +
    "10: import pkg from '@mui/material/locale/index.js';\n" +
    '           ^\n' +
    '11: const { esES } = pkg;',
  watchFiles: [
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/app/entry.client.tsx',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/app/routes/_index.tsx',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/app/root.tsx',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/package.json',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/react/jsx-runtime.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/react/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/react-dom/client.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/browser.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/components.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/scroll-restoration.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/single-fetch.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/server.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/react-router-dom/dist/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/react/cjs/react-jsx-runtime.production.min.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/react-dom/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/react/cjs/react.production.min.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/app/tailwind.css',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/_virtual/_rollupPluginBabelHelpers.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/data.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/markup.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/invariant.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/turbo-stream/dist/turbo-stream.mjs',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/errorBoundaries.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/routes.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/react-router-dom/server.mjs',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/cookies.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/server.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/responses.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/single-fetch.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/formData.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/sessions.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/sessions/cookieStorage.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/sessions/memoryStorage.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/router/dist/router.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/upload/errors.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/upload/memoryUploadHandler.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/dev.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/tailwind.config.ts',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/errors.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/react-router/dist/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/routeModules.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/links.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/react/dist/esm/fallback.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/cookie/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/warnings.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/errors.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/entry.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/headers.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/mode.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/invariant.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/routeMatching.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/serverHandoff.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/routes.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/deprecations.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@web3-storage/multipart-parser/esm/src/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/locale/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/set-cookie-parser/lib/set-cookie.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/data.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@remix-run/server-runtime/dist/esm/markup.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@web3-storage/multipart-parser/esm/src/search.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@web3-storage/multipart-parser/esm/src/utils.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/colors/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/utils/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/AccordionDetails/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Accordion/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/AccordionActions/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/styles/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/AccordionSummary/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Autocomplete/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Alert/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Avatar/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/AlertTitle/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/AppBar/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/AvatarGroup/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Backdrop/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Badge/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/BottomNavigation/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/BottomNavigationAction/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Breadcrumbs/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Button/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Box/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/ButtonGroup/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/ButtonBase/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Card/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/CardActionArea/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/CardActions/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/CardContent/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/CardHeader/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/CardMedia/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Checkbox/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Chip/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/CircularProgress/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/ClickAwayListener/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Collapse/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/Container/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/CssBaseline/index.js',
    '/Users/nicopm/WebstormProjects/remix_spa_mui_repro/node_modules/@mui/material/darkScrollbar/index.js',
    ... 1001 more items
  ],
  [Symbol(augmented)]: true
}

Tried using vite-plugin-cjs-interop, noExternal, and serverModuleFormat: 'cjs' in vite.config.ts to fix this error without success.

Notice that even though the file mentioned in the error above (node_modules/@mui/material/locale/index.js) does not have a default export (the recommended fix included in the error message doesn't work), npm run build works fine when I set ssr: true in vite.config.ts.
I know this does not make sense in a SPA app, but I found this because I'm trying to migrate the frontend of a regular Remix app to a SPA one (and the frontend code builds just fine in the regular Remix app).

@npapagna npapagna changed the title Material UI breaks Remix SPA build Material UI breaks Remix SPA build (but works fine in regular Remix apps) Jun 18, 2024
@brophdawg11
Copy link
Contributor

This has come up before and I believe the underlying issue is that MUI is not properly configured for ESM/CJS which fails the Remix server build. Even in SPA mode, Remix does a server build so it can render your root component on the server at build time to generate the index.html file.

The best workaround I know of is to put any MUI (or otherwise non-server-friendly code) in your entry.client. In your case, wrap the ThemeProvider around RemixBrowser instead of putting it in your root layout.

startTransition(() => {
  hydrateRoot(
    document,
    <StrictMode>
      <ThemeProvider theme={createTheme(esES)}>
        <CssBaseline />
        <RemixBrowser />
      </ThemeProvider>
    </StrictMode>
  );
});

@brophdawg11 brophdawg11 added package:dev external feat:spa Issues related to SPA Mode labels Jun 20, 2024
@npapagna
Copy link
Contributor Author

Thanks a lot, @brophdawg11. That makes sense.
It's working fine now.

@brophdawg11 brophdawg11 closed this as not planned Won't fix, can't repro, duplicate, stale Jun 24, 2024
@npapagna
Copy link
Contributor Author

@brophdawg11 I've been working on this, and even thought the cliend side works fine, this solution means we cannot use the theme in the server. This makes it hard to use MUI to render the HydrateFallback and use the same theme as the rest of the app.

I tried remix({serverBuildFile: 'index.cjs', serverModuleFormat: 'cjs'}) in vite.config.ts but it breaks the build with the following error:

/Users/nicopm/WebstormProjects/npapagna/remix-mui/node_modules/@mui/material/locale/index.js:1
export const amET = {
^^^^^^

SyntaxError: Unexpected token 'export'
    at internalCompileFunction (node:internal/vm:73:18)
    at wrapSafe (node:internal/modules/cjs/loader:1176:20)
    at Module._compile (node:internal/modules/cjs/loader:1218:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Function.Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19)
    at require (node:internal/modules/cjs/helpers:110:18)
    at Module.<anonymous> (/Users/nicopm/WebstormProjects/npapagna/remix-mui/build/server/index.cjs:11:18)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)

Looking at the package.json definition in node_modules/@mui/material/locale/package.json, It looks like require is trying lo load the ESM module instead the CJS one:

{
  "sideEffects": false,
  "module": "./index.js",
  "main": "../node/locale/index.js",
  "types": "./index.d.ts"
}

const index_js = require("@mui/material/locale/index.js");

Is there any way to make this work in the server side without bundling material packages via noExternal?

@brophdawg11
Copy link
Contributor

From what I understand, MUI needs to fix their published package files and package.json to be CJS/ESM compliant.

@alanxp
Copy link

alanxp commented Jul 4, 2024

why was this closed with no answer?

@brophdawg11
Copy link
Contributor

Because OP stated

It's working fine now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants