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

Add cjs support #203

Merged
merged 4 commits into from
Aug 27, 2021
Merged

Add cjs support #203

merged 4 commits into from
Aug 27, 2021

Conversation

antonmedv
Copy link
Collaborator

@antonmedv antonmedv commented Aug 23, 2021

Fixes #197

@cspotcode
Copy link
Contributor

At a glance, looks good. esbuild might be faster unless rollup has features that you need.

@antonmedv
Copy link
Collaborator Author

@antongolub take a look, please. What do you think?

@antongolub
Copy link
Collaborator

@antonmedv, I,m 3* today, so I’m a little out of shape)) May I take a look tomorrow?

.github/scripts/build.mjs Outdated Show resolved Hide resolved
.github/scripts/build.mjs Outdated Show resolved Hide resolved
package.json Show resolved Hide resolved
.github/scripts/build.mjs Outdated Show resolved Hide resolved
@antonmedv
Copy link
Collaborator Author

Also, what about moving global pollution to zx.mjs in this version?

And keep the library index.mjs free of global extension?

@antongolub
Copy link
Collaborator

Definitely agree: remove global side effects from index and introduce global.mjs for that.

@antonmedv
Copy link
Collaborator Author

antonmedv commented Aug 24, 2021

How many people are going to actually do import 'zx/global'?

What about package - no globals, zx binary - with globals approach?

Will create a separate PR for after this one.

@antonmedv
Copy link
Collaborator Author

Thoughts about ESM&CJS duality:

But on other hand it will be definitely easier for projects still in CJS only modes.

@antongolub
Copy link
Collaborator

I see it this way:

index.mjs   // contains zx inners
global.mjs  // injects some zx api to global, has own d.ts
cli.mjs // bin entry point: parses args, builds exec context, invokes target script

@antongolub
Copy link
Collaborator

antongolub commented Aug 24, 2021

Well, dual packages need some additional costs in building and testing. But this is the only way to provide a smooth transition from cjs to esm epoch.

@cspotcode
Copy link
Contributor

#198 avoids the dual package hazard. On the other hand, what dual package hazards do you expect to exist for zx?

You could avoid it by taking the same approach here, writing an .mjs that exposes the .cjs bundle as named exports.

@antonmedv
Copy link
Collaborator Author

global.mjs will not work with bundle everything cjs approach.

@antonmedv
Copy link
Collaborator Author

@cspotcode how in your pr globby is required? How cjs will be able to export it?

@cspotcode
Copy link
Contributor

cspotcode commented Aug 24, 2021

#198 does a bit of a hack for globby, which does have limitations.

If you await glob(); it will work, because it waits for globby to be imported() async.

If you glob.sync(); without first doing await glob; it'll fail. So that's the limitation / hack. await glob; waits for globby to import()

EDIT: the goal here was to preserve the experience for MJS consumers. They will still have a fully unchanged, native experience. CJS consumers will, at most, need to add await glob; to their code. I was trying to keep everything ESM-first, following your stated philosophy.


As I understand it, anything that needs to be cjs compatible simply needs to load synchronously, so it needs to live in a cjs file. Then you can use a mjs shim to expose it as named exports for mjs consumers. The same philosophy should work for global.mjs, right? global.cjs can apply the side-effects to the global object.

@antonmedv
Copy link
Collaborator Author

This is really odd limitation. I prefer dual package 📦

@cspotcode
Copy link
Contributor

You can avoid that limitation and avoid dual package, right?

@antonmedv
Copy link
Collaborator Author

Nope. And we want to develop package as esm for future.

And drop cjs support in one/two tears.

@cspotcode
Copy link
Contributor

I'm saying if the .mjs provides named exports that come from the .cjs, then you avoid the dual-package hazards. mjs consumers get the same API they always have, and cjs support is added. And the code is still written as an ECMAScript module, meaning a clean drop of cjs in the future.

Doesn't matter to me which way it's accomplished, but it's good to understand the issue.

@antonmedv
Copy link
Collaborator Author

I didn’t get it. How?

  1. we want to develop esm version
  2. Provide cjs
  3. Globby is esm only

@cspotcode
Copy link
Contributor

cspotcode commented Aug 24, 2021

The idea I'm thinking about is:

  1. keep index.mjs the way it is, versioned in git. Develop esm version.
  2. keep build step compiling index.mjs to index.cjs
  3. Do not publish index.mjs. Instead publish imports.mjs which has import lib from './index.cjs'; const {glob, $, ...} = lib; export {glob, $, ...};
  4. configure package.json exports so that ESM consumers receive imports.mjs and CJS consumers receive index.cjs

Usage is unchanged for ESM consumers:

import {glob} from 'zx';
await glob();

Usage for TS consumers:

import {glob} from 'zx';
import {foo} from './patterns';
glob.sync(foo);

Usage for CommonJS consumers:

const {glob} = require('zx');
glob.sync();

And require('zx').glob === await import('zx').glob because it's the same code underneath.

It can reduce install size, too, since it ships only a single copy of the code and deps. Though I don't think install size is a concern for a tool like zx.

EDIT fixed code in bullet point 3 at the top

@antonmedv
Copy link
Collaborator Author

antonmedv commented Aug 24, 2021

I got it. Cool idea. Let's me think it through. Will update PR.

@antonmedv
Copy link
Collaborator Author

Got another problem with my PR. It reexports too much:

[ ⠴
  '$',
  'DEFAULT_FILE_SYSTEM_ADAPTER',
  'FILE_SYSTEM_ADAPTER',
  'ProcessOutput',
  'ProcessPromise',
  '__esModule',
  'argv',
  'cd',
  'chalk',
  'createFileSystemAdapter',
  'default',
  'encloseBrace',
  'escapeLast',
  'escapeNode',
  'escapeRegex',
  'exceedsLimit',
  'exists',
  'fetch',
  'find',
  'flatten',
  'fs',
  'glob',
  'globby',
  'hasRegexChars',
  'isInteger',
  'isInvalidBrace',
  'isObject',
  'isOpenOrClose',
  'isRegexChar',
  'isWindows',
  'nothrow',
  'question',
  'read',
  'reduce',
  'removeBackslashes',
  'removePrefix',
  'sleep',
  'supportsLookbehinds',
  'toPosixSlashes',
  'wrapOutput',
  'write',
  'writev'
]

@antonmedv
Copy link
Collaborator Author

Not really good. :( Supporting both already seems complicated.

@antonmedv
Copy link
Collaborator Author

I was not able to find a solution. So no cjs support, I guess.

@cspotcode
Copy link
Contributor

cspotcode commented Aug 25, 2021 via email

@antonmedv
Copy link
Collaborator Author

Yes, looks like it is rollup issue.

@cspotcode
Copy link
Contributor

Seems like esbuild handles this, and we can use a proper resolve plugin instead of find-and-replace for node: builtins. I reopened and pushed the code to #198.

@cspotcode cspotcode mentioned this pull request Aug 27, 2021
@antonmedv
Copy link
Collaborator Author

After lots of thinking 💭 🧐 I think this is the best compromise. Like one package inside another. So I'm ok with accepting dual package hazards. rollup produces a much nicer output and requires only Node.js to run (in this case is good, no need for speed here). And mjs is the future prove.

@antonmedv antonmedv merged commit 303feea into main Aug 27, 2021
@antonmedv antonmedv deleted the cjs branch August 27, 2021 20:37
@cspotcode
Copy link
Contributor

Did you figure out a fix for #203 (comment)?

@antonmedv
Copy link
Collaborator Author

Yes, same as you did. Just create and index.cjs file with "filtering".

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

Successfully merging this pull request may close these issues.

Publish sync CJS entrypoint to allow ts-node without --loader
3 participants