Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't esbuild multiple files unless I use unix find #424

Closed
c0debreaker opened this issue Oct 3, 2020 · 31 comments
Closed

Can't esbuild multiple files unless I use unix find #424

c0debreaker opened this issue Oct 3, 2020 · 31 comments

Comments

@c0debreaker
Copy link

I also don't see index.html file in dist directory.

The command I used was

find . -name 'src/*.js' -exec esbuild {} --bundle --outdir=dist --minify --sourcemap --loader:.js=jsx --external:common/Loadable --external:components/MainContent/ThemeChooser --external:components/MainContent/BuildInfoRegion --external:stores/ThemeStylesStore --external:helpers/ThemeManager --external:stores/ThemeStylesStore --external:common/StyledListItem --external:common/StyledSubheader \;

I'm also wondering why I have to add --external since I wrote them.

It's a ReactJS application.

@evanw
Copy link
Owner

evanw commented Oct 3, 2020

Can't esbuild multiple files unless I use unix find

It is probably possible to bundle multiple files by using the wildcard expansion feature of your shell such as src/**/*.js without using find. Otherwise this is a reasonable way to do things. You could also pass esbuild a list of files to process using the JavaScript or Go API if find is unwieldy. You're right that esbuild doesn't have this feature built in, but that's just because it's not designed for this specific use case. See also issue #263.

I also don't see index.html file in dist directory.

I don't understand why you would expect that giving esbuild some JavaScript files would generate a HTML file.

If you are trying to pass esbuild a HTML file as an input and are expecting it to parse the HTML file for files to bundle, this is a future feature that will likely be added at some point but that doesn't currently exist. I am using issue #31 to track that feature request.

I'm also wondering why I have to add --external since I wrote them.

It looks like you are telling esbuild to bundle each file with --bundle. Bundling means "scan over all dependencies recursively and create a single file containing all of those files" so if you don't want to bundle, you can just omit --bundle. Then you won't need to mark any files as external.

@c0debreaker
Copy link
Author

Ah, I was under the impression that esbuild works like a webpack which creates a ready bundled website. How do I introduce esbuild to my existing project where I use webpack to generate a site under dist directory?

@nettybun
Copy link

nettybun commented Oct 3, 2020

@c0debreaker I come from a webpack background myself and still don't know why you were you expecting an HTML file... In webpack your need to explicitly use an HTML plugin (like html-webpack-plugin) since webpack, like esbuild, is a bundler not a HTML generator.

For esbuild it'll be easiest to write some kind of postbuild step either in NodeJS or Bash. Personally I have an index.html in src/ and cp it to dist/

@c0debreaker
Copy link
Author

I mentioned in last comment that I thought esbuild works the same as webpack and I was wrong.

I can write a script to do that. I'm seeing filenames didn't get modified by esbuild. Looks like I can get a hash string of the final file in dist then inject that filename in index.html, then finally put it in dist.

With that, I can stop using webpack. Correct?

@c0debreaker
Copy link
Author

Apology, I'm still very confused with esbuild.

The command I executed was

$ esbuild src/**/*.js --outdir=dist --minify --loader:.js=jsx '--define:process.env.NODE_ENV="production"'

This is the new dist/index.js that esbuild generated. Looks like it only made the code block as a single line.

import o from"./rum";import r from"react";import e from"react-dom";import{Route as t,BrowserRouter as m}from"react-router-dom";import p from"./App";o.setInitialPageLoadName("BuildViewer Frontend"),e.render(r.createElement(m,null,r.createElement(t,{path:"/",component:p})),document.getElementById("root"));

If I specify index.js in index.html like below, I feel like it's not going to work. It looks like I am missing steps.

<script src="index.js"></script>

@evanw
Copy link
Owner

evanw commented Oct 4, 2020

What are you trying to do? I'm still not clear on what specifically you are trying to do (e.g. what are the steps). Are you trying to bundle src/index.js and its dependencies into dist/index.js, and copy src/index.html to dist/index.html with <script src="index.js"></script> inserted into it? Or something else?

@c0debreaker
Copy link
Author

I have an existing ReactJS project where I use npm run build that puts files in dist. Once the process is done, I upload it to our webserver. What I'd like to accomplish using esbuild is similar to that. I'm aware that esbuild is not an HTML generator like @heyheyhello mentioned earlier. That's why I wrote a script that copies index.html into dist. The index.html has a code <script src="index.js"></script>

Yesterday, I executed esbuild src/**/*.js --outdir=dist --minify --loader:.js=jsx '--define:process.env.NODE_ENV="production"'. It created dist directory and all the files that esbuild parsed - https://i.imgur.com/8HkUBHI.png

What I want to accomplish is to make a web application ready using esbuild and some other scripts that I will write. I tried serving dist as a website but I encountered an error - https://i.imgur.com/I0hqhoD.png It's because it hasn't transpiled it yet to a format readable by browsers.

@nettybun
Copy link

nettybun commented Oct 4, 2020

Use esbuild --bundle src/index.js (...rest of your options)

Let esbuild walk your files and dependencies for you, don't use **/* else that will ask esbuild to consider each file in isolation, which is why you're ending up with all the individual files instead of a single bundle. Currently you're producing an ESM bundle, but that's not what you want. Use --format (see --help for options) to produce a bundle that doesn't use import statements like CJS or IIFE.

@c0debreaker
Copy link
Author

c0debreaker commented Oct 4, 2020

I've done that before and when I do that, I get the errors below. Is it because I am using .env file where it contains NODE_PATH=src? How do I tell esbuild to use src directory as the referene NODE_PATH to build from?

$ esbuild --bundle src/index.js --minify --loader:.js=jsx
src/App.js:6:21: error: Could not resolve "common/Loadable" (mark it as external to exclude it from the bundle)
import Loadable from 'common/Loadable';
                     ~~~~~~~~~~~~~~~~~
src/App.js:15:23: error: Could not resolve "components/MainContent/ThemeChooser" (mark it as external to exclude it from the bundle)
  loader: () => import('components/MainContent/ThemeChooser')
                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/App.js:19:23: error: Could not resolve "components/MainContent/BuildInfoRegion" (mark it as external to exclude it from the bundle)
  loader: () => import('components/MainContent/BuildInfoRegion')
                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/stores/ThemeStylesStore.js:15:22: error: Could not resolve "helpers/ThemeManager" (mark it as external to exclude it from the bundle)
import AllThemes from 'helpers/ThemeManager';
                      ~~~~~~~~~~~~~~~~~~~~~~
src/components/MainContent/index.js:4:29: error: Could not resolve "stores/ThemeStylesStore" (mark it as external to exclude it from the bundle)
import ThemeStylesStore from 'stores/ThemeStylesStore';
                             ~~~~~~~~~~~~~~~~~~~~~~~~~
src/components/Navigation/index.js:7:27: error: Could not resolve "common/StyledListItem" (mark it as external to exclude it from the bundle)
import StyledListItem from 'common/StyledListItem';
                           ~~~~~~~~~~~~~~~~~~~~~~~
src/components/Header/index.js:5:29: error: Could not resolve "stores/ThemeStylesStore" (mark it as external to exclude it from the bundle)
import ThemeStylesStore from 'stores/ThemeStylesStore';
                             ~~~~~~~~~~~~~~~~~~~~~~~~~
src/components/Navigation/index.js:18:28: error: Could not resolve "common/StyledSubheader" (mark it as external to exclude it from the bundle)
import StyledSubheader from 'common/StyledSubheader';
                            ~~~~~~~~~~~~~~~~~~~~~~~~
src/components/Navigation/index.js:21:29: error: Could not resolve "stores/ThemeStylesStore" (mark it as external to exclude it from the bundle)
import ThemeStylesStore from 'stores/ThemeStylesStore';
                             ~~~~~~~~~~~~~~~~~~~~~~~~~
9 errors

Below is the directory structure of src directory

$ tree src
src
├── App.js
├── App.test.js
├── common
│   ├── FlightBoardEffect
│   │   ├── assets
│   │   │   └── style.css
│   │   └── index.js
│   ├── Loadable
│   │   └── index.js
│   ├── Panel
│   │   └── index.js
│   ├── Spinner
│   │   └── index.js
│   ├── StyledListItem
│   │   └── index.js
│   └── StyledSubheader
│       └── index.js
├── components
│   ├── Header
│   │   ├── Logo
│   │   │   ├── assets
│   │   │   │   ├── cpanel.png
│   │   │   │   └── reactlogo.png
│   │   │   └── index.js
│   │   └── index.js
│   ├── MainContent
│   │   ├── BuildInfoRegion
│   │   │   ├── BuildInfo
│   │   │   │   ├── BuildInfoCell.js
│   │   │   │   ├── BuildInfoTable.js
│   │   │   │   ├── assets
│   │   │   │   │   └── gitlab.svg
│   │   │   │   └── index.js
│   │   │   └── index.js
│   │   ├── ThemeChooser
│   │   │   └── index.js
│   │   └── index.js
│   ├── Navigation
│   │   └── index.js
│   └── Profile
│       ├── assets
│       │   └── face.png
│       └── index.js
├── helpers
│   ├── ThemeManager
│   │   ├── Themes
│   │   │   ├── DarkMatter.js
│   │   │   ├── Florida.js
│   │   │   ├── Gogo.js
│   │   │   ├── GoldenState.js
│   │   │   ├── Midnight.js
│   │   │   └── Salmon.js
│   │   └── index.js
│   └── reactrocks.js
├── index.js
├── logo.svg
├── registerServiceWorker.js
├── rum.js
└── stores
    ├── ThemeStylesStore.js
    └── WebAppsBuildInformationStore.js

24 directories, 37 files

@nettybun

This comment has been minimized.

@nettybun
Copy link

nettybun commented Oct 4, 2020

Similar to tsconfig.json in TS, you should be able to use jsconfig.json to specify "paths" and "baseUrl". Here's a test that shows it's possible in esbuild:

func TestJsconfigJsonBaseUrl(t *testing.T) {
tsconfig_suite.expectBundled(t, bundled{
files: map[string]string{
"/Users/user/project/src/app/entry.js": `
import fn from 'lib/util'
console.log(fn())
`,
"/Users/user/project/src/jsconfig.json": `
{
"compilerOptions": {
"baseUrl": "."
}
}
`,
"/Users/user/project/src/lib/util.js": `
module.exports = function() {
return 123
}
`,
},

@c0debreaker
Copy link
Author

Just got home. I'll try it now. Thanks!

@evanw
Copy link
Owner

evanw commented Oct 4, 2020

Is it because I am using .env file where it contains NODE_PATH=src? How do I tell esbuild to use src directory as the referene NODE_PATH to build from?

Ah, I see. Yes this sounds like the issue. I'm not home at the moment so I don't have any solutions right now, but I can look at this later.

@c0debreaker
Copy link
Author

c0debreaker commented Oct 4, 2020

@heyheyhellow, it failed

$ esbuild --bundle src/index.js --minify --loader:.js=jsx --jsconfig=jsconfig.json
error: Invalid build flag: "--jsconfig=jsconfig.json"

and using --tsconfig

$ esbuild --bundle src/index.js --minify --loader:.js=jsx --tsconfig=tsconfig.json
src/App.js:6:21: error: Could not resolve "common/Loadable" (mark it as external to exclude it from the bundle)
import Loadable from 'common/Loadable';
                     ~~~~~~~~~~~~~~~~~
src/App.js:15:23: error: Could not resolve "components/MainContent/ThemeChooser" (mark it as external to exclude it from the bundle)
  loader: () => import('components/MainContent/ThemeChooser')
                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/App.js:19:23: error: Could not resolve "components/MainContent/BuildInfoRegion" (mark it as external to exclude it from the bundle)
  loader: () => import('components/MainContent/BuildInfoRegion')
                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/components/Header/index.js:5:29: error: Could not resolve "stores/ThemeStylesStore" (mark it as external to exclude it from the bundle)
import ThemeStylesStore from 'stores/ThemeStylesStore';
                             ~~~~~~~~~~~~~~~~~~~~~~~~~
src/stores/ThemeStylesStore.js:15:22: error: Could not resolve "helpers/ThemeManager" (mark it as external to exclude it from the bundle)
import AllThemes from 'helpers/ThemeManager';
                      ~~~~~~~~~~~~~~~~~~~~~~
src/components/MainContent/index.js:4:29: error: Could not resolve "stores/ThemeStylesStore" (mark it as external to exclude it from the bundle)
import ThemeStylesStore from 'stores/ThemeStylesStore';
                             ~~~~~~~~~~~~~~~~~~~~~~~~~
src/components/Navigation/index.js:7:27: error: Could not resolve "common/StyledListItem" (mark it as external to exclude it from the bundle)
import StyledListItem from 'common/StyledListItem';
                           ~~~~~~~~~~~~~~~~~~~~~~~
src/components/Navigation/index.js:18:28: error: Could not resolve "common/StyledSubheader" (mark it as external to exclude it from the bundle)
import StyledSubheader from 'common/StyledSubheader';
                            ~~~~~~~~~~~~~~~~~~~~~~~~
src/components/Navigation/index.js:21:29: error: Could not resolve "stores/ThemeStylesStore" (mark it as external to exclude it from the bundle)
import ThemeStylesStore from 'stores/ThemeStylesStore';

@c0debreaker
Copy link
Author

Is it because I am using .env file where it contains NODE_PATH=src? How do I tell esbuild to use src directory as the referene NODE_PATH to build from?

Ah, I see. Yes this sounds like the issue. I'm not home at the moment so I don't have any solutions right now, but I can look at this later.

Thanks a lot! 😊

@c0debreaker
Copy link
Author

Hi @evanw, were you able to figure it out?

@nettybun
Copy link

nettybun commented Oct 6, 2020 via email

@c0debreaker
Copy link
Author

c0debreaker commented Oct 6, 2020

Here it is @heyheyhello

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "Node",
    "baseUrl": ".",
    "paths": {
      "components/*": [
        "src/components/"
      ],
      "common/*": [
        "src/common/"
      ]
    }
  }
}

and the command

$ esbuild --bundle src/index.js --minify --loader:.js=jsx --jsconfig=jsconfig.json

@nettybun
Copy link

nettybun commented Oct 6, 2020

Want to just try:

{ 
  "compilerOptions":
    "baseUrl": "." 
  }
} 

Since that worked in Evan's tests

@c0debreaker
Copy link
Author

I got the same error when I used --jsconfig, https://i.imgur.com/jmrMIMe.png

and if using --tsconfig, https://i.imgur.com/xeatlO2.png

@nettybun
Copy link

nettybun commented Oct 6, 2020

I'm not sure then. I don't think you need to specify --tsconfig or --jsconfig, I think just having a jsconfig.json, as you do, should be enough. I can't figure out how the tests are run - it's all in Go. Maybe Evan can comment on that test vs your case. Good luck!

@c0debreaker
Copy link
Author

Thanks a lot! I really hope we'll be able to figure this out. There's a lot of project at work that can benefit from this. It will save huge amount in build time.

@c0debreaker
Copy link
Author

c0debreaker commented Oct 6, 2020

I finally got it to work even without specifying jsconfig.json by editing my source code from

import Loader from 'react-loadable';
import LoadingSpinner from 'common/Spinner';

const Loadable = (opts) =>
  Loader({
    loading: LoadingSpinner,
    delay: 150,
    ...opts
  });

export default Loadable;

to

import Loader from 'react-loadable';
import LoadingSpinner from 'src/common/Spinner';

const Loadable = (opts) =>
  Loader({
    loading: LoadingSpinner,
    delay: 150,
    ...opts
  });

export default Loadable;

We will have to edit hundreds of application git repositories that uses .env file. That's going to be very painful.

@nettybun
Copy link

nettybun commented Oct 6, 2020 via email

@c0debreaker
Copy link
Author

c0debreaker commented Oct 6, 2020

yep but tons of repositories that will have to edit. I'm going to clone esbuild and see if I can make changes to it and add a feature I need.

@c0debreaker
Copy link
Author

c0debreaker commented Oct 6, 2020

@evanw @heyheyhello what parameter should I pass to fix this error?

src/components/MainContent/BuildInfoRegion/BuildInfo/BuildInfoTable.js:7:19: error: File extension not supported: src/components/MainContent/BuildInfoRegion/BuildInfo/assets/gitlab.svg
import gitlab from './assets/gitlab.svg';

@nettybun
Copy link

nettybun commented Oct 6, 2020

#236 (comment)

Did you try searching the issues and reading the docs? This should work.

@c0debreaker
Copy link
Author

I did search yesterday but didn't find it. Thanks a lot. I'll let you know.

@c0debreaker
Copy link
Author

No more errors! Finally, esbuild completed successfully. However, I'm wondering where my png files are https://i.imgur.com/7Sz1ttE.png

@nettybun
Copy link

nettybun commented Oct 6, 2020 via email

@c0debreaker
Copy link
Author

I haven't but I tried serving the generated dist directory to see if the site will load on my browser. There is an error which is case property being undefined. I'll continue troubleshooting.
https://i.imgur.com/5s1AVMY.png
https://i.imgur.com/kkD3FnU.png

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants
@evanw @c0debreaker @nettybun and others