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

node bundling #192

Closed
mihailik opened this issue Dec 10, 2017 · 22 comments
Closed

node bundling #192

mihailik opened this issue Dec 10, 2017 · 22 comments
Labels
💬 RFC Request For Comments

Comments

@mihailik
Copy link

🙋 feature request

Other bundlers (like webpack) can target node environment instead of browser. That largely involves leaving things like require('fs') and process intact in the code.

Is there a way to do the same in parcel?
If no, is it on the roadmap?

Ideally I'd want to test it by parcelling the parcel itself, and getting a bundled single JS file.

@davidnagli
Copy link
Contributor

That’s an interesting point. I don’t think we deal with target environments like Node yet. It would just bundle everything just like it would for the browser. I think it’s something we should look into though.

Out of curiousity... why would you ever want to bundle your Node scripts?

@mihailik
Copy link
Author

Well, the most obvious reason is performance. One file instead of thousands mean MUCH faster install times, and slightly faster runtime.

It also cricumvents tough versioning situations: end users can install-uninstall whatever they like, but my bundled package will always behave exactly the same way.

Not meant for every library on NPM, but useful in some cases. Could be especially priceless for corporate environments in fact (human effort to check, mandate, verify 3rd party external components is proportional to package count).

@kidandcat
Copy link
Contributor

You cannot bundle dependencies, because some of them may change things like environment or OS configuration, and all of those tasks are usually executed in the installation phase.

And about the bundling, zero performance will be achieved in runtime because when you launch your program, all the code gets into memory. The bundling is effective in the browser because you can fetch all your code faster, but you are not accelerating your processing speed in any way.

For example, there are already a lot of NodeJS compilers (for example http://enclosejs.com/). But all of them will especify that you will not win any perforn

@davidnagli davidnagli added the 💬 RFC Request For Comments label Dec 10, 2017
@fathyb
Copy link
Contributor

fathyb commented Dec 10, 2017

This can be extremely useful when compiling a React app to Node.js for service side rendering (with css modules), where we would require all JavaScript dependencies but bundle the others.

@mihailik
Copy link
Author

mihailik commented Dec 10, 2017

To be clear on performance: in certain cases there's runtime win in bundling. Resolving a module requires several full-blown OS calls through kernel, FS drivers and back. Modules living in node_modules even more so: traversing FS trees, loading package.json etc. Bundling all modules in one file completely eliminates these low-level OS costs, at a price of parsing larger file upfront.

Having huge dependency tree with hundreds of tiny modules magnify FS-specific costs, that's where bundling would help runtime performance.

Of course the installation wins are more pronounced than runtime in any case: latency and costs of accessing FS are miniscule comparing to latencies and costs of accessing NPM registry. Resolving version between hundreds of packages, downloading all of them, decompressing and creating all those files locally takes time. Dealing with a single package eliminates majority of this work.

@EduardoRFS
Copy link

Other obvious benefit of bundling, babel in dependencies, your package is running on AWS, with node 4 or 6, using babel to replace async / await by Bluebird generators give a huge boost performance

@eXon
Copy link
Contributor

eXon commented Dec 12, 2017

There are other ways to do server-rendering with parcel. You don't actually needs to bundle it, just run it through babel. Here is a great example supporting import ignore on css/anything you need: https://github.com/reactivestack/parcel-react-ssr

@eXon
Copy link
Contributor

eXon commented Dec 12, 2017

Oh and also parcel bundle are actually running on node.js easily. The only thing you can't is export a function in the bundle and require it from node.

@calebboyd
Copy link

calebboyd commented Dec 13, 2017

@davidnagli
I work on nexe (and also use it heavily) and I'd be really interested in helping if its something you choose to pursue.

I started experimenting here.. Which is essentially the start of yet another bundler. Mostly just need correct dynamic module resolution and good extension points for a virtual file system.

There are also a lot of edge cases for native modules (.node files)

@sublimeye
Copy link

sublimeye commented Dec 18, 2017

@eXon Isn't it the whole point of ParcelJS to have zero configuration and Automatically transforms modules system?

  • React components are written with ES6 modules + JSX (both not supported by node yet)
  • Or what about TypeScript on the server?

ParcelJS already supports TypeScript and lots of other features – it would be really cool if it could support Universal Web Apps the same out of the box way. (Without a separate configuration for the server)

@Chathula
Copy link

+1 for this.

@egtzori
Copy link

egtzori commented Jan 24, 2018

webpack does this with a single parameter.
exclude: /node_modules/,

all thats needed, is NOT to process files that matches /node_modules/

@lbguilherme
Copy link
Contributor

Just made a pull request that introduces a node mode. Please give it a try and see if it works for you.

@jrop
Copy link

jrop commented Feb 15, 2018

I think the new --target=node option is great. However, I kind of wish the --target=node behavior would be the following instead: Bundle node_modules selectively: only bundle node_modules that appear in "devDependencies".

In webpack, this is achievable as follows:

const builtins = require('builtin-modules')
const DEPS = Object.keys(require('./package').dependencies || {})
module.exports = {
  // ...
  externals: (context, request, callback) => {
    [request] = request.split('/') // this doesn not take into account package names like "@scope/pkg"
    if (DEPS.includes(request) || builtins.includes(request))
      return callback(null, 'commonjs ' + request) // exclude from bundle
    callback() // include in bundle
  },
  // ...
}

This way, I get the following gains:

  • I can bundle JS-only deps with my app (put them in devDependencies)
  • Native addons can still be listed in dependencies, and are not bundled

@DeMoorJasper
Copy link
Member

@jrop this sounds like a pretty bad idea as devDependencies doesn't seem to be meant for this purpose?

@lbguilherme
Copy link
Contributor

lbguilherme commented Feb 15, 2018 via email

@jrop
Copy link

jrop commented Feb 15, 2018

@lbguilherme

devDependencies should not be required by the project at all, thus shouldn't be bundled

See my use-case below.

If you somehow can't bundle a part of the things, then what is the advantage of bundling the other part?

This is a good point, and is one I have considered. Supposing I am writing a library, and I want to produce a UMD bundle to publish as a package, purely for the startup benefits of not having to require 1k's of files from the file-system. In this way I can bundle "as much as possible", and list a native lib as a dependency so that somebody can "npm install" my package.

@DeMoorJasper However, by definition, they are dependencies required only for development. Here is a use-case (albeit a corner-case):

  • I want to develop a utility script to distribute to a member of my team who does not use NodeJS/NPM/etc.
  • My script relies on, say, inquirer and node-fetch.
  • In this case, my end-goal is to bundle these JS-only dependencies so that I can distribute a single JS file to my colleague, who can then chmod u+x some.js && ./some.js my file.

To accomplish this, my project would in fact list "inquirer" and "node-fetch" as devDependencies, as they are only required for development.

@jrop
Copy link

jrop commented Feb 15, 2018

Also, there was some previous discussion on this already (for the record) in some PR file comments:

https://github.com/parcel-bundler/parcel/pull/652/files#r164348823

@lbguilherme
Copy link
Contributor

lbguilherme commented Feb 15, 2018

This is a good point, and is one I have considered. Supposing I am writing a library, and I want to produce a UMD bundle to publish as a package, purely for the startup benefits of not having to require 1k's of files from the file-system. In this way I can bundle "as much as possible", and list a native lib as a dependency so that somebody can "npm install" my package.

If this is a library, then bundling its dependencies on the package is a bad practice for node. Some libraries bundle their own code in a single file, but they still require their node_modules dependencies, so that they can be updated or shared between multiple libraries. Bundling everything is bad here.

But if you still want to do that, that's ok... Just bundle everything. Native modules will be supported in a following pull request.

In this case, my end-goal is to bundle these JS-only dependencies so that I can distribute a single JS file to my colleague, who can then chmod u+x some.js && ./some.js my file.

Again, this is solved by just bundling everything. Parcel will only bundle what is in fact required by the source, so you shouldn't have to do anything special to separate some packages. As parcel is today, it will not read your "dependencies" for anything.

A believe both your usecases are covered by --target=node --bundle-node-modules.

See #796

@ddragosd
Copy link

ddragosd commented Jun 9, 2018

FWIW, when targeting Node, instead of using process.env.* use global.process.env.*

@ptitjes
Copy link

ptitjes commented Apr 18, 2021

About native modules, I have the code for bundling them working already. After this is reviewed and merged, I'll open a new pull request with it.

Hi @lbguilherme, I don't seem to find your merge request about native modules. Is the current state of parcel 2 beta 2 can bundle node native addons ? If not, can anyone give me guidance on how to use includeNodeModules to exclude native modules and generate a "bundled" node_modules with only the native modules ? Or is it not the way to go ?

@FDiskas
Copy link

FDiskas commented Nov 3, 2021

I added to my package.json something like

  "targets": {
    "main": {
      "context": "node",
      "isLibrary": true,
      "sourceMap": false,
      "outputFormat": "commonjs",
      "includeNodeModules": {
        "typescript": false,
        "vscode": false
      }
    }
  },

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

No branches or pull requests