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

Is there a ESM version? #208

Open
Dmitri-Sintsov opened this issue Apr 22, 2021 · 17 comments
Open

Is there a ESM version? #208

Dmitri-Sintsov opened this issue Apr 22, 2021 · 17 comments

Comments

@Dmitri-Sintsov
Copy link

Can you provide a link to ESM version, please? Also perhaps adding it to the README.

@alexei
Copy link
Owner

alexei commented Apr 23, 2021

Oh, did they finally decide to fix Node?

Jokes aside, how would that work? I.e. supporting CommonJS and ESM at the same time.

@Dmitri-Sintsov
Copy link
Author

That works via providing separate sprintf.esm.js file. Which would use export sprintf, not module.exports.

I use it with modern browsers and with rollup.js, not in node.

@Dmitri-Sintsov
Copy link
Author

I run rollup.js in Deno.

@Dmitri-Sintsov
Copy link
Author

One may look how underscore.js provides their esm distribution, for example.

@alexei
Copy link
Owner

alexei commented Apr 23, 2021

I didn't know about that, and I'm even more confused today than I was yesterday: I thought the way to do it was .mjs?

@Dmitri-Sintsov
Copy link
Author

.mjs extension is optional one (for disambiguation), it's not required. Chrome / Firefox load ES modules finely from ordinary .js file ES modules.

https://underscorejs.org/underscore-esm.js

Deno works with ES modules natively, although it's typescript (.ts) by default.

https://deno.land/manual/examples/import_export

@alexei
Copy link
Owner

alexei commented Apr 23, 2021

So let me get this straight: first there was CJS, then AMD showed up for whatever reason, then that evolved into UMD. Now we have ESM. Browsers don't mind .js, but Node wants .mjs. And now this: .esm.js which I still don't understand where it came from and the Internet doesn't help either. This looks like a mess I don't want to deal atm. Sorry!

@Dmitri-Sintsov
Copy link
Author

As you wish. If one does not like esm.js, you may create sprintf.mjs though. It will work with modern browsers and with Deno. By the way, the author of Deno hopes that Deno will replace node.js at some point.

@Dmitri-Sintsov
Copy link
Author

For example, underscore.js is major library which provides different versions, including ESM one.

@alexei
Copy link
Owner

alexei commented Apr 23, 2021

Is there any documentation about this?

@Dmitri-Sintsov
Copy link
Author

See underscore.js build setup for example:

https://github.com/jashkenas/underscore/blob/97f4cb42a1125e160f8aac1bedcd4969745dffec/rollup.config.js

  // Monolithic ESM bundle for browsers and deno.
  {
    input: 'modules/index-all.js',
    treeshake: false,
    output: monolithConf({
      file: 'underscore-esm.js',
      format: 'esm',
    }),
  },

@rickynguyen4590
Copy link

It will be nice if we could support ESM version, I have to see this warning everyday ...

copyright.component.ts depends on 'sprintf-js'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

@jimmywarting
Copy link

Many are just doing a major release and ship it as esm-only
ppl stuck with cjs can use dynamic import() or stay on the later version.

@viT-1
Copy link

viT-1 commented Jan 21, 2022

As you wish. If one does not like esm.js, you may create sprintf.mjs though. It will work with modern browsers and with Deno. By the way, the author of Deno hopes that Deno will replace node.js at some point.

Alternative package with esm support: printj and same discussion about alternative way if esm will not be supported =). But I don't found both on cdnjs.

@SheetJSDev
Copy link

The approach used in printj is to build the ESM script with a .mjs extension and use the module field in package.json to point to the .mjs script. The main field points to the CJS version and we ship the minified dist scripts for standalone use in the browser. This approach does not break normal node require statements. Webpack will accept the extension. Node ESM is sated. Browser ESM (script type="module") accepts it. Older browsers can theoretically use the dist version without fear.

If you're comfortable with the idea of supporting ESM but don't want to be burdened with having to maintain two separate scripts, it's sensible to build the ESM script from the base script using gulp-replace. Strip the IIFE and replace the exports/window blocks with a single export statement:

  1. add the module line to package.json as well as the gulp-replace dev dep:
--- a/package.json
+++ b/package.json
@@ -4,6 +4,7 @@
   "description": "JavaScript sprintf implementation",
   "author": "Alexandru Mărășteanu <hello@alexei.ro>",
   "main": "src/sprintf.js",
+  "module": "dist/sprintf.mjs",
   "scripts": {
     "test": "mocha test/*.js",
     "pretest": "npm run lint",
@@ -25,6 +26,7 @@
     "gulp-header": "^2.0.5",
     "gulp-mocha": "^6.0.0",
     "gulp-rename": "^1.4.0",
+    "gulp-replace": "^1.1.3",
     "gulp-sourcemaps": "^2.6.4",
     "gulp-uglify": "^3.0.1",
     "mocha": "^5.2.0"
  1. create a gulp task to create that file from your base file:
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -8,6 +8,7 @@ var pkg         = require('./package.json'),
     header      = require('gulp-header'),
     eslint      = require('gulp-eslint'),
     mocha       = require('gulp-mocha'),
+    replace     = require('gulp-replace'),
     benchmark   = require('gulp-benchmark'),
     banner      = '/*! <%= pkg.name %> v<%= pkg.version %> | Copyright (c) 2007-present, <%= pkg.author %> | <%= pkg.license %> */\n'
 
@@ -42,4 +43,15 @@ gulp.task('dist', ['test'], function() {
         .pipe(gulp.dest('dist'))
 })
 
-gulp.task('default', ['dist'])
+gulp.task('dist-esm', ['test'], function() {
+    return gulp.src([
+        'src/sprintf.js'
+    ])
+        .pipe(replace(/^[^]*?{/, ""))
+        .pipe(replace(/if \(typeof exports[^]*$/, "export { sprintf, vsprintf };"))
+        .pipe(rename({ extname: '.mjs' }))
+        .pipe(header(banner, {pkg: pkg}))
+        .pipe(gulp.dest('dist'))
+})
+
+gulp.task('default', ['dist', 'dist-esm'])

(you may also want to update dist/.gitattributes)

This approach works in a simple webpack import, in node 16 ESM, and in raw browser ESM.

@viT-1 unpkg and jsdelivr pull from the npm modules e.g. https://unpkg.com/sprintf-js@1.1.2/dist/sprintf.min.js . The live demo linked in that thread imports from unpkg directly and it would roughly work the same way if the same approach is used here:

      import { sprintf } from 'https://unpkg.com/printj@1.2.0/printj.mjs';

@Etienne-M
Copy link

+1 On this issue! I'm happy to help if need be. With newer build tools, it shouldn't be hard to produce this library in multiple formats.

@mozey
Copy link

mozey commented Jun 15, 2023

I managed to convert NPM package for sprinft.js to an ESM using esh.sh

From the deno docs: "esm.sh is a CDN that was specifically designed for Deno... uses esbuild to take an arbitrary npm package and ensure that it is consumable as an ES Module"

This worked in the browser with the bundle I create with esbuild_deno_loader, but VSCode (the Deno extension) complained with: "This expression is not callable... has no call signatures.deno-ts(2349)" wherever I used sprintf in my TypeScript source code. Maybe I didn't configure the IDE properly? 🤷

Anyway... I then saved the ESM that was generated by esm.sh to a file, and did a relative import

import { sprintf } from "./sprintf/sprintf.esm.js"

This works, both the browser and the IDE is happy

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

8 participants