This plugin allows you to start a local server with hot reloading with Esbuild

esbuild-dev-server

This plugin allows you to start a local server with hot reloading with Esbuild

Installation

npm

npm i esbuild-dev-server -D

yarn

yarn add esbuild-dev-server -D

go

go get github.com/Falldot/esbuild-dev-server

Configuration

  • options.Port, string: local server start port.
  • options.Index, string: path to index html file.
  • options.StaticDir, string: path to static files (js, css, img ...).
  • options.WatchDir, string: path to working directory.
  • options.OnLoad, () => void: local server restart event.

How to use?

Node.js

const {build, formatMessages} = require("esbuild");
const {esBuildDevServer, startServer, sendError, sendReload} = require("esbuild-dev-server");

;(async () => {
	const builder = await build({
		entryPoints: ["src/index.js"],
		bundle: true,
		minify: false,
		sourcemap: true,
		target: ['chrome58', 'firefox57', 'safari11', 'edge16'],
		outdir: "dist/js",
		incremental: true,
		plugins: [
			esBuildDevServer({
				Port: "8080",
				Index: "dist/index.html",
				StaticDir: "dist",
				WatchDir: "src",
				OnLoad: async () => {
					try {
						await builder.rebuild();
						await sendReload();
					} catch(result) {
						let str = await formatMessages(result.errors, {kind: 'error', color: true});
						await sendError(str.join(""));
					}
				}
			})
		],
	});
	await startServer();
})();

Golang

package main

import (
	"log"

	devserver "github.com/Falldot/esbuild-dev-server"
	"github.com/evanw/esbuild/pkg/api"
)

func main() {
	var result api.BuildResult

	result = api.Build(api.BuildOptions{
		EntryPoints:       []string{"src/index.js"},
		Bundle:            true,
		MinifyWhitespace:  true,
		MinifyIdentifiers: true,
		MinifySyntax:      true,
		Outdir:      "dist/js",
		Write:       true,
		Engines: []api.Engine{
			{api.EngineChrome, "58"},
			{api.EngineFirefox, "57"},
			{api.EngineSafari, "11"},
			{api.EngineEdge, "16"},
		},
		Incremental: true,
		Plugins: []api.Plugin{
			devserver.Plugin(devserver.Options{
				Port:      ":8080",
				Index:     "dist/index.html",
				StaticDir: "dist",
				WatchDir:  "src",
				OnReload: func() {
					result.Rebuild()
				},
			}),
		},
	})
	if len(result.Errors) > 0 {
		log.Fatalln(result.Errors)
	}

	if err := devserver.Start(); err != nil {
        log.Fatalln(result.Errors)
    }
}
Owner
Vladislav Fedotov
JS/TS, SASS/SCSS, Vue, Veux Nuxt, React, Redux, Recoil, Jest, Mocha, Next Electron, Node, Go, Docker, MongoDB, PostgreSQL, MySQL, C/C++, SDL2, EASTL
Vladislav Fedotov
Comments
  • Not working with React

    Not working with React

    I did the following:

    • Set everything up with the default config
    • Created a single React page src/index.tsx (see code below)
    • Changed the config with entryPoints: ["src/index.tsx"].
    • Ran node config/esbuild.config.js

    Expected result:

    • The page loads.

    Actual result:

    • The page is blank.
    • In the console it says Uncaught SyntaxError: Unexpected token '<'
    • In the network tab I see that it has fetched index.js, but the response body was just the text inside the index.html

    src/index.tsx:

    import React, { useCallback, useState } from "react";
    import ReactDOM from "react-dom";
    
    const App = (props: { message: string }) => {
        const [count, setCount] = useState(0);
        const increment = useCallback(() => {
            setCount(count => count + 1);
        }, [count]);
        return(<>
            <h1>{props.message}</h1>
            <h2>Count: {count}</h2>
            <button onClick={increment}>Increment</button>
        </>)
    };
    
    window.addEventListener('load', () => {
        console.log('Loaded!');
        ReactDOM.render(
            <App message="Hello World! Simple Counter App built on ESBuild + React + Typescript"/>,
            document.getElementById('root')
        );
    }, {
        once: true
    });
    
  • Can't find the JS file

    Can't find the JS file

    I'm not sure what am I doing wrong, but the point is I can't figure.

    Here's my directory structure: /utils/devServer.js - contains the esbuildDevServer configuration file /src/app.tsx - my 'app' /public/dist/index.html - html file exactly as per example

    When I run the esbuildDevServer everything goes well... when I try to browse my application I get: Uncaught SyntaxError: Unexpected token '<' (at app.js:1:1)

    Which points to the HTML file as far as I know this error could mean it can't find the .js file.

    Here's my esbuildevserver configuration: const {build} = require("esbuild") const esBuildDevServer = require("esbuild-dev-server")

    esBuildDevServer.start(
        build({
            entryPoints: ['./src/app.tsx'],
            bundle: true,
            minify: false,
            sourcemap: true,
            incremental: true,
            metafile: true,
            target: ['chrome58', 'safari11'],
            outdir: './public/dist'
        }),
        {
            port: '8080',
            watchDir: './src',
            index: 'public/dist/index.html',
            staticDir: 'public/dist',
            onBeforeRebuild: {},
            onAfterRebuild: {}
        }
    )
    

    here is my 'app'

    import React from 'react';
    import { createRoot } from 'react-dom/client'
    
    const App = () => {
        return (
        <div>
            Hello World!
        </div>
        )
    }
    
    
    const root = createRoot(document.getElementById('root'))
    
    root.render(<App/>)
    

    here is my html file

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8"/>
            <title>Esbuild & React bundle</title>
        </head>
        <body>
            <div id="root"></div>
            HTML
            <script src="app.js"></script>
        </body>
    
    </html>
    
    

    What can i possibly be doing wrong?

  • Issues with static files and ESBuild loader

    Issues with static files and ESBuild loader

    Hello,

    I'm having issues configuring esbuild-dev-server to work.

    This is my current esBuildDevServer configuration:

    esBuildDevServer.start(
        build({
            entryPoints: ['./index.tsx'],
            bundle: true,
            minify: false,
            sourcemap: true,
            incremental: true,
            platform: 'browser',
            target: ['chrome58', 'safari11'],
            loader: { 
                '.png': "file", 
                '.hdr': 'file', 
                '.jpg': 'file',
                '.otf': 'file',
                '.ttf': 'file'
            },
            plugins: [
                stylePlugin({
                    postcss: {
                        plugins: [
                            postcssImport,
                            postcssNesting,
                            autoprefixer                        
                        ]
                    }
                }),
                copyFilePlugin({
                    source: ['utils/reset.css'],
                    target: ['../../public/client/static'],
                    copyWithFolder: false
                }),
                svgPlugin()
            ],
            outdir: '../../public/client/static'
        }),
        // To run the dev server a permission change is necessary:
        // chmod u+x node_modules/esbuild-dev-server-darwin-x64/devserver
        {
            port: '8080',
            watchDir: './',
            index: '../../public/client/index.html',
            staticDir: '../../public/client/',
            onBeforeRebuild: {},
            onAfterRebuild: {}
        }
    )
    

    And this is my current file structure: Screen Shot 2022-10-25 at 11 41 58 am

    As you can see things are apparently in place, although when I open my application, the very first view tries to load the image (logo-DGF6IMCN.png), which fails because the path is wrong as the picture below shows: Screen Shot 2022-10-25 at 11 43 14 am

    I understand my files are going to this path due my outdir configuration right? If I change that parameter to '../../plublic/client', then the files get copied to the 'proper' path but the esbuild-dev-server understands any request on this path to be a route, so I'm kinda lost on how to configure it to work properly.

    The only way I can currently get it to work is if I set the loader to data-url, which is far from be ideal.

    Can you guys please advise? Thanks

  • All requests resolve to index.html

    All requests resolve to index.html

    I've got this plugin set up and running a dev server, however all network requests resolve to the index.html file. This includes requests for my index.js file, which of course fails.

    Would you be able to help me figure this out? I can provide more info if you tell me what you need.

  • hot reload intermittently fails

    hot reload intermittently fails

    Occasionally evt.Data is 'reload\nreload' instead of just 'reload', causing the console.error branch to be taken in the reload script. I'll see 3-4 successful reloads, then 1-2 failed reloads, then a few successful, etc.

    I'm using the linux-x64 server running on Unbuntu under Windows 10 using WSL 2.0. I see the behavior in Chrome, Firefox, and Edge running under Windows on the same host.

    It's hard to tell, but it might be happening more often if I have Chrome, Firefox, and Edge all open at the same time, vs. just one of them. When I do have more than one browser open, they ALMOST always either succeed or fail together, but occasional one will work while the others fail.

    Seems like race condition of some sort. Wouldn't be noticeable if the reload script ignored the value.

  • onBeforeRebuild and onAfterRebuild never trigger

    onBeforeRebuild and onAfterRebuild never trigger

    I could be wrong but I don't think that these two callbacks ever actually get triggered. I don't see then mentioned anywhere in the esbuild-dev-server.js source as well.

        port            : "8080",
        watchDir        : "src",
        index           : "dist/index.html",
        staticDir       : "dist",
        onBeforeRebuild : () => console.log("onBeforeRebuild"),
    
  • [Feature Request] proxy setting

    [Feature Request] proxy setting

    Hey, great plugin.

    One of the remaining things for us to migrate to this from Webpack dev server is use of the proxy feature.

    see: https://webpack.js.org/configuration/dev-server/#devserverproxy

    this allows us to map an endpoint to a path so we can hit the api for example. Is this something you can support?

  • UnhandledPromiseRejectionWarning: Error: spawn /Users/user/template/node_modules/esbuild-dev-server/lib/../../esbuild-dev-server-darwin-x64/devserver EACCES

    UnhandledPromiseRejectionWarning: Error: spawn /Users/user/template/node_modules/esbuild-dev-server/lib/../../esbuild-dev-server-darwin-x64/devserver EACCES

    when i use this plugin, an error occurred

    (node:63759) UnhandledPromiseRejectionWarning: Error: spawn /Users/react-esbuild-template/node_modules/esbuild-dev-server/lib/../../esbuild-dev-server-darwin-x64/devserver EACCES
        at Process.ChildProcess._handle.onexit (internal/child_process.js:269:19)
        at onErrorNT (internal/child_process.js:467:16)
        at processTicksAndRejections (internal/process/task_queues.js:82:21)
    (Use `node --trace-warnings ...` to show where the warning was created)
    (node:63759) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
    (node:63759) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
    

    and esbuild code is:

    const esbuild = require('esbuild');
    const { lessLoader } = require('esbuild-plugin-less');
    const { htmlPlugin } = require('@craftamap/esbuild-plugin-html');
    const esBuildDevServer = require("esbuild-dev-server")
    
    const htmlPluginOptions = {
        files: [
            {
                entryPoints: [
                    'src/app.tsx',
                ],
                filename: 'index.html',
                htmlTemplate: `
                    <!DOCTYPE html>
                    <html lang="en">
                    <head>
                        <meta charset="UTF-8">
                        <meta name="viewport" content="width=device-width, initial-scale=1.0">
                        <title>React-esbuild-template</title>
                    </head>
                    <body>
                        <div id="root">
                        </div>
                    </body>
                    </html>
                `,
            },
        ]
    }
    
    const options = {
        entryPoints: ['src/app.tsx'],
        bundle: true,
        metafile: true, // needs to be set
        outdir: 'dist/', // needs to be set
        plugins: [
            htmlPlugin(htmlPluginOptions),
            lessLoader()
        ],
        loader: {
            '.ts': 'ts',
        },
    }
    
    esBuildDevServer.start(
            esbuild.build(options),
            {
                port:      "10002", // optional, default: 8080
                watchDir:  "src", // optional, default: "src"
                index:     "dist/index.html", // optional
                staticDir: "dist", // optional
                onBeforeRebuild: {}, // optional
                onAfterRebuild:  {}, // optional
            }
    )
    
    
A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.
A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.

frp README | 中文文档 What is frp? frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the Internet. As of now, it s

Jan 5, 2023
Multiplexer over TCP. Useful if target server only allows you to create limited tcp connections concurrently.

tcp-multiplexer Use it in front of target server and let your client programs connect it, if target server only allows you to create limited tcp conne

May 27, 2021
4chain is a simple、fast reverse proxy to help you expose a local server behind a NAT or firewall to the Internet.

4Chain What is 4chain? 4chain is a simple、fast reverse proxy to help you expose a local server behind a NAT or firewall to the Internet. Using the ssh

Nov 1, 2022
Minekube Connect allows you to connect any Minecraft server

Minekube Connect allows you to connect any Minecraft server, whether online mode, public, behind your protected home network or anywhere else in the world, with our highly available, performant and low latency edge proxies network nearest to you.

Dec 27, 2022
Coredns plugin for relaying .local domains

CoreDNS Local_Query This is a plugin for coredns that was developed to allow for the use of naked hosts in place of .local domains i.e example.local b

Nov 4, 2021
Powered by Matterbridge, MatterAMXX is a plugin for AMXX that allows simple bridging between your game servers, Mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, and more.
Powered by Matterbridge, MatterAMXX is a plugin for AMXX that allows simple bridging between your game servers, Mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, and more.

Powered by Matterbridge, MatterAMXX is a plugin for AMXX that allows simple bridging between your game servers, Mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, and more.

Dec 27, 2022
A minimal analytics package to start collecting traffic data without client dependencies.

go-web-analytics A minimal analytics package to start collecting traffic data without client dependencies. Logging incoming requests import "github.co

Nov 23, 2021
The plugin serves as a starting point for writing a Mattermost plugin

Plugin Starter Template This plugin serves as a starting point for writing a Mattermost plugin. Feel free to base your own plugin off this repository.

Dec 10, 2021
Feb 10, 2022
Cf-cli-find-app-plugin - CF CLI plugin to find applications containing a search string

Overview This cf cli plugin allows users to search for application names that co

Jan 3, 2022
Twitter-plugin - Falco Plugin for Twitter Stream

Twitter Plugin This repository contains the twittter plugin for Falco, which fol

Mar 17, 2022
A wrapper for cloudflared that manages your local proxies for you

Cloudflared Tunnel Wrapper cfdtunnel is a wrapper for cloudflared access tunnel, designed to access multiple tunnels without having to worry about you

Dec 16, 2022
Chat app that allows you to group multiple channels into one view.

hashchat Backend service Getting Started Essential steps to get your backend service deployed A helloworld example has been shipped with the template

Dec 13, 2021
This is a tool that allows you to check minecraft names availability, this tool can do around 3000~ names a minute or more!

Checker This is a tool that allows you to check minecraft names availability, this tool can do around 3000~ names a minute or more! Tutorial To instal

Feb 13, 2022
Allows you to programatically modify key:value sysctl pairs on MacOS

go-sysctl-mac Allows you to programatically modify key:value sysctl pairs on MacOS. Tested & confirmd to work on MacOS Big Sur & newer releases. Examp

Dec 4, 2021
Helps you to send ssh commands to target machine in your local network from outside via gRPC
Helps you to send ssh commands to target machine in your local network from outside via gRPC

rpc-ssh In case, you don't want to make your ssh port accessible from outside local network. This repository helps you to send ssh commands to target

Nov 16, 2022
A tool allows you to inspect in-bound and out-bound dns messages
A tool allows you to inspect in-bound and out-bound dns messages

This tool allows you to inspect in-bound and out-bound dns messages. You can use the tool to poison your own cache. Call ./dns-mitm to start the appli

Dec 11, 2021
DeepCopy a portable app that allows you to copy all forms of specified file types from your entire file system of the computer

DeepCopy a portable app that allows you to copy all forms of specified file types from your entire file system of the computer

Dec 20, 2021
A local web-server for mocking channel responses

Local Channel Mock This is application is intended to mock the ISO channel during the development of a new integration. Exposed endpoints By default,

Dec 27, 2021