Search code examples
typescriptparceljssolid-js

Parcel fails to resolve 'solid-js/jsx-runtime' for TSX files


I'm migrating a React Webpack project into a SolidJS Parcel project. However, the combination of SolidJS and Parcel seems to have problems with nested Typescript projects, which combinations of React and Webpack do not have.

In my minimal example project, I get the error: @parcel/core: Failed to resolve 'solid-js/jsx-runtime' from './foo/src/index.tsx'. If I try to rename, index.tsx into index.jsx, Parcel can build the same file without any error. However, I want to use Typescript instead of JavaScript.

/.babelrc:

{
  "presets": [ "solid" ]
}

/package.json:

{
  "private": true,
  "dependencies": {
    "solid-js": "1.3.12"
  },
  "devDependencies": {
    "babel-preset-solid": "1.3.12",
    "parcel": "2.3.2",
    "typescript": "4.6.2"
  }
}

/tsconfig.json:

{
    "compilerOptions": {
        "isolatedModules": true,
        "jsx": "preserve",
        "jsxImportSource": "solid-js",
        "lib": [
            "dom",
            "es2021"
        ],
        "module": "commonjs",
        "noEmit": true,
        "noImplicitAny": true,
        "noImplicitReturns": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "sourceMap": true,
        "strict": true,
        "target": "es5"
    }
}

/foo/src/index.tsx:

export function HelloWorld() {
  return <div>Hello World!</div>;
}

/foo/package.json:

{
  "private": true,
  "source": "src/index.tsx",
  "scripts": {
    "parcel:build": "npx parcel build"
  }
}

How can I fix the error @parcel/core: Failed to resolve 'solid-js/jsx-runtime in my nested Typescript project?


Solution

  • To run solid in parcel, you need to follow these steps:

    1. Install babel-preset-solid and @babel/core.

    2. Create a .babelrc file with the following content:

    {
      "presets": ["solid"]
    }
    

    Parcel automatically picks up babel configuration but it is best to stick to the json based configuration:

    Parcel supports both project wide config files such as babel.config.json, as well as file relative configs such as .babelrc.

    Note: JavaScript Babel configs (e.g. babel.config.js) should be avoided. These cause Parcel’s caching to be less effective, which means all of your JS files will be recompiled each time you restart Parcel.

    As a side note, we don't need to provide babel-transform-runtime for parcel to work:

    @babel/preset-env and @babel/plugin-transform-runtime are not necessary, since transpilation for your browser targets is handled automatically by Parcel. https://parceljs.org/languages/javascript/#babel

    1. Add hot module replacement (HMR) support if you like:
    import { render } from 'solid-js/web';
    import { App } from './App';
    const dispose = render(() => <App />, document.body);
    
    if (module.hot) {
      module.hot.accept();
      module.hot.dispose(dispose);
    }
    

    If you run into any problem, make sure you have properly set your workspace:

    package.json file

    {
      "name": "parcel-solid-demo",
      "source": "src/index.html",
      "browserslist": "> 0.5%, last 2 versions, not dead",
      "scripts": {
        "start": "parcel",
        "build": "parcel build",
        "serve": "parcel serve"
      },
      "devDependencies": {
        "babel-preset-solid": "^1.6.10",
        "@babel/core": "^7.21.0",
        "parcel": "^2.8.3"
      },
      "dependencies": {
        "solid-js": "^1.6.11"
      }
    }
    

    index.html file in the "source" directory from the package.json:

    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="utf-8"/>
        <title>My First Parcel App</title>
        <link rel="stylesheet" href="style.css" />
        <script type="module" src="index.tsx"></script>
      </head>
      <body>
      </body>
    </html>
    

    tsconfig.json content:

    {
      "compilerOptions": {
        "jsx": "preserve",
        "jsxImportSource": "solid-js",
        "noEmit": true
      }
    }