Замена EsBuild StartService

Я новичок в esBuild и ReactJS, и, следуя руководству, я решил создать собственное приложение CLI Transpiling. Я дошел до того, что ввожу текст в текстовое поле, но на консоли в клиенте появилось следующее сообщение об ошибке. Версия хоста «0.8.27» не соответствует двоичной версии «0.9.0». Я знаю, что использую старую версию, я попытался сначала найти способ решить проблему, просмотрев документацию, поскольку они полностью выбросили метод startService() в новой версии. Но я не смог найти никакого возможного решения моей проблемы, есть ли кто-нибудь, кто может помочь мне решить эту проблему. Вот мой код, который должен запустить транспилинг:

      const startService = async () => {
ref.current = await esbuild.startService({
  worker: true,
  wasmURL: '/esbuild.wasm'
})
  }

 useEffect(() => {
    startService()
  }, [])

  const onClick = async () => {
    if (!ref.current) {
      return;
    }
    const result = await ref.current.build({
      entryPoints: ['index.js'],
      bundle: true,
      write: false,
      plugins: [unpkgPathPlugin()]
    })
    console.log(result );
    setCode(result)
  }

5 ответов

Решение

Документация по запуску esbuild в браузере находится здесь: https://esbuild.github.io/api/#running-in-the-browser . В версии 0.9.0 esbuild.startService() стал esbuild.initialize() а также service.build() стал esbuild.build()(т.е. явный объект службы исчез). Итак, обновленный код может выглядеть примерно так:

      const startService = async () => {
  await esbuild.initialize({
    worker: true,
    wasmURL: '/esbuild.wasm'
  })
  ref.current = true
}

useEffect(() => {
  startService()
}, [])

const onClick = async () => {
  if (!ref.current) {
    return;
  }
  const result = await esbuild.build({
    entryPoints: ['index.js'],
    bundle: true,
    write: false,
    plugins: [unpkgPathPlugin()]
  })
  console.log(result);
  setCode(result)
}

Обратите внимание, что при работе в браузере асинхронный API недоступен. Кроме того, я не хотел бросать «уже инициализировано» каждый раз, когда я перезагружаюсь во время редактирования. Вот как я это настроил:

      import { useState, useEffect } from 'react';
import './App.css';
import * as esbuild from 'esbuild-wasm';

function App() {
  const [input, setInput] = useState('');
  const [code, setCode] = useState('');

  useEffect(() => {
    // This ugly code is to avoid calling initialize() more than once
    try {
      esbuild.build({});
    } catch (error) {
      if (error instanceof Error && error.message.includes('initialize')) {
        esbuild.initialize({
          worker: false,
          wasmURL: '/esbuild.wasm',
        });
      } else {
        throw error;
      }
    }
  }, []);

  const onClick = () => {
    esbuild
      .transform(input, {
        loader: 'jsx',
        target: 'es2015',
      })
      .then((result) => {
        setCode(result.code);
      });
  };

  return (
    <div className="App">
      <textarea
        value={input}
        onChange={(e) => setInput(e.target.value)}></textarea>
      <div>
        <button onClick={onClick}>Submit</button>
      </div>
      <pre>{code}</pre>
    </div>
  );
}

export default App;

Ребят, у меня есть решение получше, можно горячую перезагрузку и без ошибок.

      const startService = async () => {
if (!window.isEsbuildRunning) {
    await esbuild.initialize({
      worker: true,
      wasmURL: '/esbuild.wasm'
    })
}
    window.isEsbuildRunning = true;
    ref.current = true
  }
  
  useEffect(() => {
    startService()
  }, [])
  
  const onClick = async () => {
    if (!ref.current) {
      return;
    }
    const result = await esbuild.build({
      entryPoints: ['index.js'],
      bundle: true,
      write: false,
      plugins: [unpkgPathPlugin()]
    })
    console.log(result);
    setCode(result)
  }

Придумал лучший способ:

      import * as esbuild from "esbuild-wasm";

const startService =  (() => {
    let esBuildRef: any;
    return async() => {
        if (esBuildRef) {
            return esBuildRef
        } else {
            await esbuild.initialize({
                worker: true,
                wasmURL: "./esbuild.wasm"
            });
            esBuildRef = esbuild;
            return esBuildRef;
        }
    }
})()

export default startService;

используйте его как

      
import { useState, useEffect } from 'react';
import startService from './plugins/esbuild';

export default function Home() {
  const [input, setInput] = useState('');
  const [code, setCode] = useState('');

  const submitHandler = async() => {
    const esBuildRef =  await startService();
    console.log(esBuildRef);
    const result = await esBuildRef.transform(input, {
      loader: 'jsx',
      target: 'es2015'
    })
    setCode(result.code);
  }

  return (
    <main>
      <textarea value = {input} onChange={(e) => setInput(e.target.value)}>

      </textarea>
      <div onClick={submitHandler}>
        Submit
      </div>
      <pre>
        {code}
      </pre>
    </main>
  )
}

Шаблон синглтон

Я догадываюсь, откуда взялся этот вопрос. Предыдущий ответ верен, но если в setCode(result) затем прокомментируйте это некоторое время.

Другие вопросы по тегам