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

Support for ES6 Modules #1723

Open
marktyers opened this issue Oct 24, 2020 · 12 comments
Open

Support for ES6 Modules #1723

marktyers opened this issue Oct 24, 2020 · 12 comments
Assignees
Labels

Comments

@marktyers
Copy link

Is there a timescale for Handlebars supporting ES6 modules?

This would allow it to be imported into JS modules without needing to add it to the html page head as a UMD module.

Cheers.

@jaylinski
Copy link
Member

Related to #1707, #1696.

@jaylinski jaylinski self-assigned this Dec 23, 2021
@hybridherbst
Copy link

Hi @jaylinski, I've seen that both these referenced issues have been resolved but no new release made yet.
Is there a rough ETA for ES6 support? Just curious, no pressure :)

@Tythos
Copy link

Tythos commented Oct 15, 2022

Theoretically, there should be a way to add an additional grunt task under "webpack" option to utilize the experimental "module" library type:

https://webpack.js.org/configuration/output/#type-module

I'm experimenting with some options but haven't found the right way to synthesize the configurations yet. But all you really need is to replace the UMD header with a simple "export default" followed by the factory closure and invocation. I'll report with (hopefully) an MR if I find something that works; unfortunately my Grunt and Webpack knowledge are minimal, so no guarantees.

@jaylinski
Copy link
Member

@Tythos I'd rather replace our outdated grunt/webpack v1 build with a new rollup or https://github.com/developit/microbundle build. But for our 4.x branch, a solution like yours may fit better.

@Tythos
Copy link

Tythos commented Oct 15, 2022

Understood. With the webpack major version breaking (currently "^1.12.6", whereas the module feature remains experimental even in 5+), it's probably not an option anyway just for this feature. Instead, I just added a non-umd build output (which gets the "var Handlebars = {...closure}" treatment) that was then appended with "export default Handlebars". It's manual and dirty for now, but it does work very well and I've captured it in a gist for easy submodule-inclusion.

@thibauld
Copy link

thibauld commented Apr 30, 2023

+1 would love handlebars to support ES6 modules as well :)

@Sparticuz
Copy link

@Tythos

I just added a non-umd build output (which gets the "var Handlebars = {...closure}" treatment) that was then appended with "export default Handlebars"

Can you please elaborate on this? What options did you use when precompiling your templates? I'm struggling getting them working with converting my codebase to modules.

@Sparticuz
Copy link

Sparticuz commented May 2, 2023

Here is my solution:

diff --git a/node_modules/handlebars/bin/handlebars b/node_modules/handlebars/bin/handlebars
index 7749121..878a36c 100755
--- a/node_modules/handlebars/bin/handlebars
+++ b/node_modules/handlebars/bin/handlebars
@@ -15,6 +15,11 @@ var argv = parseArgs({
     'description': 'Exports amd style (require.js)',
     'alias': 'amd'
   },
+  'esm': {
+    'type': 'string',
+    'description': 'Exports ECMAScript module style, path to Handlebars module (eg. "handlebars/lib/handlebars")',
+    'default': null
+  },
   'c': {
     'type': 'string',
     'description': 'Exports CommonJS style, path to Handlebars module',
diff --git a/node_modules/handlebars/dist/cjs/precompiler.js b/node_modules/handlebars/dist/cjs/precompiler.js
index 9e6cd63..0989921 100644
--- a/node_modules/handlebars/dist/cjs/precompiler.js
+++ b/node_modules/handlebars/dist/cjs/precompiler.js
@@ -180,7 +180,7 @@ module.exports.cli = function (opts) {
   }

   // Force simple mode if we have only one template and it's unnamed.
-  if (!opts.amd && !opts.commonjs && opts.templates.length === 1 && !opts.templates[0].name) {
+  if (!opts.amd && !opts.commonjs && !opts.esm && opts.templates.length === 1 && !opts.templates[0].name) {
     opts.simple = true;
   }

@@ -203,6 +203,8 @@ module.exports.cli = function (opts) {
       output.add("define(['" + opts.handlebarPath + 'handlebars.runtime\'], function(Handlebars) {\n  Handlebars = Handlebars["default"];');
     } else if (opts.commonjs) {
       output.add('var Handlebars = require("' + opts.commonjs + '");');
+    } else if (opts.esm) {
+      output.add(`import Handlebars from "${opts.esm}";`);
     } else {
       output.add('(function() {\n');
     }
@@ -258,7 +260,9 @@ module.exports.cli = function (opts) {
         output.add(['return ', objectName, ';\n']);
       }
       output.add('});');
-    } else if (!opts.commonjs) {
+    } else if (opts.esm) {
+      output.add(`export default Handlebars;`);
+    } else if (!opts.commonjs && !opts.esm) {
       output.add('})();');
     }
   }

Partially from #1816, partially from @Tythos's comment.

I'm using patch-package to run this patch.

npm install patch-package

"scripts": {
  "hbs": "handlebars .build/hbs/**.* -f dist/hbsTemplates.js --esm handlebars",
  "postinstall": "patch-package"
}

The only problem I have now is that for some reason I'm unable to use import Handlebars from "handlebars/runtime", so I'm importing from "handlebars" and it seems like it's working

@Tythos
Copy link

Tythos commented May 3, 2023

In addition to "handlebars" and "runtime" entries under the "webpack" field in "Gruntfile.js", I added another build definition:

      esm: {
        entry: './dist/cjs/handlebars.js',
        output: {
          filename: 'handlebars.mjs',
          libraryTarget: 'var'
        },
      }    

With webpack v1 (e.g., before "module" support), this generates a "handlebars.mjs" file within the "dist/" folder. In place of a UMD header, this assigns the closure return to a "var Handlebars = " expression. This can easily be replaced directly with an "export default" instead, or you can append "export default Handlebars;" to the end of the file.

That having been said, the patch above is much more comprehensive.

@Neo2308
Copy link

Neo2308 commented Jul 27, 2023

Is there a rough ETA for this getting released? This would be helpful for us.

Happy to help if there is something pending here.

Edit: Our usecase seems to have gotten resolved post v4.7.8 release. (Our usecase may not have needed es6 support)

@prinzt
Copy link

prinzt commented Dec 15, 2023

Thanks for your patch @Sparticuz !

The only problem I have now is that for some reason I'm unable to use import Handlebars from "handlebars/runtime"

Importing handlebars like this seems to work:
import Handlebars from "handlebars/lib/handlebars.runtime";

@marcodali
Copy link

Would
import * as Handlebars from "handlebars";
make the trick?

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

No branches or pull requests

9 participants