reach-sh / reach-lang

Reach: The Safest and Smartest DApp Programming Language
https://www.reach.sh
Apache License 2.0
583 stars 167 forks source link

Vitejs (build tool) incompatibility (polyfill issue) #1316

Closed leakim34 closed 1 year ago

leakim34 commented 2 years ago

Describe the error

Vitejs cannot be used with reach stdlib, since it uses some node built in modules that are not polyfilled. You'll start having multiple errors on each built in module used by reach-sh/stdlib. Starting with one of them below:

DependencyNotFoundError
Could not find dependency: 'http2' relative to '/node_modules/@reach-sh/stdlib/dist/esm/rpc_server.js'

It will do this for each built in modules used by reach.

To Reproduce

Setup a new environment with vite js using any framework you want (svelte/vue/react/..) and install reach stdlib dep.

npm create vite@latest my-vue-app -- --template vue
npm i @reach-sh/stdlib url-parse readline
npm run dev 

Import reach-sh/stdlib and instantiate it.

import { loadStdlib } from "@reach-sh/stdlib";
import MyAlgoConnect from "@reach-sh/stdlib/ALGO_MyAlgoConnect";
const reach = loadStdlib(process.env);

OR

Codesandbox test

Expected behavior

Being able to instantiate the Stdlib and use reach on vitejs. Many libraries/frameworks are using vitejs lately for its speed and ease of use instead of the heavy webpack solution.

Extra information

It would help and bring many developers that use vitejs lately, it's easy to setup & run in few seconds ! Vitejs does not plan to polyfill this in the future since it will decrease their performance and seems to be better way to handle built in module nowadays.

iGavroche commented 2 years ago

I second this request. Vite is getting harder to bypass and several frameworks (VueJS, Svelte come to mind) have started to bundle it as default.

jeapostrophe commented 2 years ago

We will work on this.

I am totally ignorant about these things, so if either of you know, please help.

My assumption #1: People that use Vite know that it is "weird" with respect to dependencies, because it changes when and where things are used.

My assumption #2: Given that, they are used to "configuring Vite to deal with it". I put that in quotes, because I have no idea how that is actually done.

I am working with analogical-thinking that Vite is like Webpack and you need to manually rewrite things --- https://github.com/reach-sh/reach-lang/blob/master/js/stdlib/webpack.config.js

Is that correct? If so, does that mean that we/Reach tell you/leakim34 what to change in your Vite configuration?

Or is there some other way we "be compatible with Vite"? Like, maybe we put in a vite.config.js and it says "Do this to http2"?

Please help!

iGavroche commented 2 years ago

@jeapostrophe my knowledge of Vite is purely circumstantial (due to my wish to use VueJS 3 and Vite being bundled with v3 by default) and I make no claim to pretend I even remotely understand Vite.

Unlike Webpack which bundles all your dependencies, Vite tries to create browser-native ES modules and load these modules on a per-request basis. I'm unsure how it ends up making our lives miserable but the bottom line is Reach stdlib makes use of crypto and buffer dependencies in a way that the usual "fixed" browser-bound packages we include and specify in the config (such as crypto and buffer) are throwing exceptions.

The simplest approach would be to start a Vue 3 standard project, include @reach-sh/stdlib, and try to get the project to build.

jeapostrophe commented 2 years ago

Thank you for the advice! Follow this issue for the solution

mannyyang commented 2 years ago

@jeapostrophe looking forward to your solution

DanBurton commented 2 years ago

Instead of

import MyAlgoConnect from "@reach-sh/stdlib/ALGO_MyAlgoConnect";

You should import it like this:

import { ALGO_MyAlgoConnect as MyAlgoConnect } from '@reach-sh/stdlib';

I've checked that this works w/ vite like so:

npm create vite@latest
# choose vanilla, typescript
cd vite-project
curl https://docs.reach.sh/reach -o reach ; chmod +x reach
./reach init
rm index.mjs
./reach compile
cp build/index.main.mjs src/bin.ts
npm install --save @reach-sh/stdlib@latest
npm install
edit src/go.ts # add contents as below
edit src/main.ts # modify as below
REACH_CONNECTOR_MODE=ALGO ./reach devnet --await-background
npm run dev
// src/main.ts
import './style.css'
import { setupGo } from './go'

document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
  <div><button id="go" type="button"></button></div>
`
setupGo(document.querySelector<HTMLButtonElement>('#go')!)
import { loadStdlib, ALGO_MyAlgoConnect as MyAlgoConnect } from '@reach-sh/stdlib'
import * as bin from './bin'
const reach = loadStdlib({REACH_CONNECTOR_MODE: 'ALGO', REACH_NO_WARN: '1'})
reach.setWalletFallback(reach.walletFallback({MyAlgoConnect}))

const go = async (e: HTMLButtonElement) => {
  const amt = reach.parseCurrency(100)
  e.innerHTML = 'getting wallet account...'
  const accA = await reach.getDefaultAccount()
  e.innerHTML = 'funding accounts from faucet...'
  await reach.fundFromFaucet(accA, amt)
  const accB = await reach.newTestAccount(amt)
  const ctcA = accA.contract(bin)
  const ctcB = accB.contract(bin, ctcA.getInfo())
  e.innerHTML = 'running...'
  await Promise.all([
    ctcA.p.Alice({}),
    ctcB.p.Bob({}),
  ])
  e.innerHTML = 'done: ' + (await ctcA.getInfo()).toString()
}

export const setupGo = (e: HTMLButtonElement) => {
  e.innerHTML = 'go'
  e.addEventListener('click', () => go(e))
}
Gungy2 commented 1 year ago

Just this line: import { loadStdlib } from '@reach-sh/stdlib' is impossible to run in a vite build. Then stdlib makes use of Express, which in turn makes of http, that needs http.ServerResponse which is not mocked by any node polyfills. Can someone clarify why a client library uses Express and other Node APIs (such as fs )? For example, I do not see the point of the file rpc_server.ts to be in the client library.

Thank you!