solidjs / solid

A declarative, efficient, and flexible JavaScript library for building user interfaces.
https://solidjs.com
MIT License
32.02k stars 913 forks source link

SolidJS using Vite, but without vite-plugin-solid ('React is not defined') #1293

Closed Marvosg closed 1 year ago

Marvosg commented 1 year ago

Describe the bug

Looking for a workaround for issue https://github.com/solidjs/vite-plugin-solid/issues/63, I am trying to run SolidJS with Vite, but without using vite-plugin-solid.

Navigating to the dev page (npm run dev) shows nothing, the console reports:

Uncaught ReferenceError: React is not defined

Looking at index.tsx in the browser debugger shows the following contents:

import { render } from "/node_modules/.vite/deps/solid-js_web.js?v=880cb05a";
render(() => /* @__PURE__ */ React.createElement("div", null, "Works"), document.getElementById("root"));

//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkQ6L05vZGVKU1Byb2plY3RzL3NvbGlkLXdpdGhvdXQtcGx1Z2luL3NyYy9pbmRleC50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcmVuZGVyIH0gZnJvbSAnc29saWQtanMvd2ViJ1xyXG5cclxucmVuZGVyKCgpID0+IDxkaXY+V29ya3M8L2Rpdj4sIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdyb290JykgYXMgSFRNTEVsZW1lbnQpXHJcbiJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBUyxjQUFjO0FBRXZCLE9BQU8sTUFBTSxvQ0FBQyxhQUFJLE9BQUssR0FBUSxTQUFTLGVBQWUsTUFBTSxDQUFnQjsiLCJuYW1lcyI6W119

Notice React.createElement.

Your Example Website or App

https://github.com/Marvosg/solidjs-without-plugin

Steps to Reproduce the Bug or Issue

  1. Check out my example repository.
  2. Change directory into folder.
  3. npm i
  4. npm run dev

Expected behavior

SolidJS should load and work.

Screenshots or Videos

No response

Platform

Additional context

Seems that Babel is not being run with the correct preset. It must be running with the default preset for tsx files, which seems to be React. I need it to run with Solid's profile.

Examples linked on the SolidJS getting started page are of two kinds, templates and Codesandbox links. All templates use vite-plugin-solid (which does not work for me due to the above mentioned issue). All Codesandbox examples use Parcel instead of Vite.

To create my example repository, I started with a vanilla-ts template for Vite:

npm create vite@latest solid-without-plugin -- --template vanilla-ts

Iinstructions on the SolidJS getting started page:

Or you can install the dependencies in your own project. To use Solid with JSX (recommended), you need to install the solid-js NPM library and the Solid JSX compiler Babel plugin:

npm install solid-js babel-preset-solid

Then add babel-preset-solid to your .babelrc, or to your Babel config in webpack or rollup:

"presets": ["solid"]

For TypeScript, set your tsconfig.json to handle Solid's JSX as follows (see the TypeScript guide for more details):

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

Vite uses Rollup under the hood. I found the official Vite doc showing how to set Rollup options from Vite.

Looking at the official Rollup docs regarding Babel, it seems that Babel is not used in Rollup by default (correct me if I am wrong). Here is what the docs say:

The easiest way to use both Babel and Rollup is with @rollup/plugin-babel. First, install the plugin:

npm i -D @rollup/plugin-babel @rollup/plugin-node-resolve

Add it to rollup.config.js:

// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';

export default {
 input: 'src/main.js',
 output: {
   file: 'bundle.js',
   format: 'cjs'
 },
 plugins: [resolve(), babel({ babelHelpers: 'bundled' })]
};

I added 'rollupOptions' to my vite.config.ts:

import { defineConfig } from 'vite'
// import solidPlugin from 'vite-plugin-solid'
import resolve from '@rollup/plugin-node-resolve'
import babel from '@rollup/plugin-babel'

export default defineConfig({
  plugins: [
    // solidPlugin(),
  ],
  build: {
    target: 'esnext',
    rollupOptions: {
      plugins: [resolve(), babel({ babelHelpers: 'bundled' })],
    },
  },
})

And a .babelrc with the following contents:

{
  "presets": ["solid"]
}

(Note: I also tried with "presets": ["babel-preset-solid"] as shown in SolidJS Codesandbox links, no change.)

So this is where I am now. How could I get SolidJS to work with Vite?

lxsmnsyc commented 1 year ago

Any particular reason why you wouldn't want to use vite-plugin-solid?

Marvosg commented 1 year ago

Yes, see https://github.com/solidjs/vite-plugin-solid/issues/63

Really I am just trying to continue my development effort, and was hoping that I might get some help with the above issue in the meantime. Ultimately I would like to use vite-plugin-solid. But currently I cannot develop with Cesium and SolidJS, since it does not work, as mentioned in the above issue.

ryansolid commented 1 year ago

If you see this issue it means the JSX is being transformed by ESBuild instead of our Babel plugin. You have to intercept it and have babel grab it but it can be tricky the way Vite optimizes deps these days. Let's just get the fix in the Vite plugin.

ryansolid commented 1 year ago

THe downstream bug is fixed in 2.3.10 of vite-plugin-ssr. I think that closes this one. If are really interested in writing your own Vite plugin maybe ask in the discussions or on Discord.

quantuminformation commented 1 year ago

I'm still getting this when using a component like so that is based in a commons repo:

export const O_Header: ParentComponent<props> = (props) => {
  return (
    <header class="h-[88px] border-b border-neutral-300 px-12 py-6">
      <nav class="flex w-full items-center justify-between">
        <div>{props.children}</div>
        <div class="flex gap-6 text-base font-medium">
          <For each={props.NavItems}>
            {(item) => (
              <A href={item.url} class="hover:text-primary-500 text-neutral-900">
                {item.text}
              </A>
            )}
          </For>
        </div>
        <div class="flex items-center gap-3 text-base font-medium">
          <A href="/help">
            <A_Icon_Hero
              name={HeroIconName.QUESTION_MARK_CIRCLE}
              supplementalClasses="text-neutral-600 hover:text-neutral-900"
            />
          </A>
          <A
            href="/profile"
            class="rounded-full border border-neutral-300 py-2 px-4 text-neutral-700 hover:border-neutral-500 hover:text-neutral-900">
            Profile
          </A>
          <A href="/signout" class="text-primary-700 hover:text-primary-900 flex items-center">
            Sign Out
            <span class="ml-[6px]">
              <A_Icon_Hero name={HeroIconName.ARROW_LEFT_ON_RECTANGLE} supplementalClasses="w-[18px]" />
            </span>
          </A>
        </div>
      </nav>
    </header>
  );
}

imported and used like so:

import { A_Icon_Custom, CustomIconName, O_Header } from 'commons';
export const App: Component = () => {
  return (
    <>
      <O_Header
        NavItems={[
          { url: '/home', text: 'Home' },
          { url: '/vendors', text: 'Vendors' },
        ]}>

o_header.tsx:26 Uncaught ReferenceError: React is not defined at O_Header (o_header.tsx:26:3) at dev.js:528:12 at untrack (dev.js:428:12) at Object.fn (dev.js:524:37) at runComputation (dev.js:709:22) at updateComputation (dev.js:692:3) at devComponent (dev.js:534:3) at createComponent (dev.js:1264:10) at _Hot$$App (app.tsx:13:3) at @solid-refresh:10:42

"devDependencies": {
    "@typescript-eslint/eslint-plugin": "^5.55.0",
    "@typescript-eslint/parser": "^5.55.0",
    "@vitest/coverage-c8": "^0.29.2",
    "eslint": "^8.36.0",
    "eslint-plugin-solid": "^0.11.0",
    "typescript": "^4.9.4",
    "vite": "^4.1.4",
    "vite-plugin-solid": "^2.6.1",
    "vitest": "^0.29.2"
  },
  "dependencies": {
    "@solidjs/router": "^0.8.0",
    "@tailwindcss/forms": "^0.5.3",
    "@tanstack/solid-table": "^8.7.9",
    "autoprefixer": "^10.4.14",
    "concurrently": "^7.6.0",
    "cross-env": "^7.0.3",
    "commons": "^0.2.2",
    "eslint-config-prettier": "^8.7.0",
    "eslint-plugin-prettier": "^4.2.1",
    "jsdom": "^21.1.1",
    "postcss": "^8.4.21",
    "postcss-import": "^15.1.0",
    "prettier": "^2.8.3",
    "prettier-plugin-tailwindcss": "^0.2.4",
    "solid-js": "^1.6.14",
    "solid-testing-library": "^0.5.1",
    "tailwindcss": "^3.2.7"
  },
/// <reference types="vitest" />
/// <reference types="vite/client" />

import { defineConfig } from 'vite';
import solid from 'vite-plugin-solid';
import packageJson from './package.json';

export default defineConfig({
  test: {
    environment: 'jsdom',
    transformMode: {
      web: [/.[jt]sx?/],
    },
    deps: {
      registerNodeLoader: true,
    },
    threads: false,
    isolate: false,
  },
  plugins: [solid()],
  resolve: {
    conditions: ['development', 'browser'],
  },
  build: {
    target: 'esnext',
  },
  define: {
    __VERSION_NUMBER__: `"${packageJson.version}"`,
  },
  server: {
    proxy: {
      '/api': {
        changeOrigin: true,
        secure: false,
        ws: true,
      },

      '/oauth2': {
        changeOrigin: true,
        secure: false,
        ws: true,
      },
    },
  },
});
quantuminformation commented 1 year ago

this fixed it in vite config


  optimizeDeps: {
    include: [],
    exclude: ['commons','.yalc']
  },```
ryansolid commented 1 year ago

Yeah ESBuild which Vite uses under the hood when optimizing assumes all JSX is React unless you provide a different JSX Factory. We don't use one. Vite Plugin Solid does a ton of work to figure out which deps should be excluded. I believe we needed to do so in a specific way as to allow Vite to still dedupe deps, as without optimization it doesn't do that properly.