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

webpack + require handlebars error #1174

Closed
abhisekp opened this issue Jan 26, 2016 · 31 comments · Fixed by #1862
Closed

webpack + require handlebars error #1174

abhisekp opened this issue Jan 26, 2016 · 31 comments · Fixed by #1862

Comments

@abhisekp
Copy link

I get the following error simply by using require handlebars.

▶ webpack --display-modules   
Hash: bdb0fe35e2f8bde783e5
Version: webpack 1.12.12
Time: 116ms
         Asset     Size  Chunks             Chunk Names
bundle.main.js  2.82 kB       0  [emitted]  main
   [0] ./src/index.js 150 bytes {0} [built]
   [1] ./~/handlebars/lib/index.js 792 bytes {0} [built] [3 warnings] [3 errors]

WARNING in ./~/handlebars/lib/index.js
require.extensions is not supported by webpack. Use a loader instead.

WARNING in ./~/handlebars/lib/index.js
require.extensions is not supported by webpack. Use a loader instead.

WARNING in ./~/handlebars/lib/index.js
require.extensions is not supported by webpack. Use a loader instead.

ERROR in ./~/handlebars/lib/index.js
Module not found: Error: Cannot resolve 'file' or 'directory' ../dist/cjs/handlebars/compiler/printer in /home/abhisekp/MyProjects/JSApps/MadeWithLove-Webpack/node_modules/handlebars/lib
 @ ./~/handlebars/lib/index.js 9:14-64

ERROR in ./~/handlebars/lib/index.js
Module not found: Error: Cannot resolve module 'fs' in /home/abhisekp/MyProjects/JSApps/MadeWithLove-Webpack/node_modules/handlebars/lib
 @ ./~/handlebars/lib/index.js 17:11-24

ERROR in ./~/handlebars/lib/index.js
Module not found: Error: Cannot resolve 'file' or 'directory' ../dist/cjs/handlebars in /home/abhisekp/MyProjects/JSApps/MadeWithLove-Webpack/node_modules/handlebars/lib
 @ ./~/handlebars/lib/index.js 7:17-50 

My index.js

var handlebars = require('handlebars');

My package.json

  "dependencies": {
    "handlebars": "^4.0.5"
  }
@benjeffery
Copy link

As mentioned in #1102 adding the line
"browser": "dist/handlebars.js",
to handlebars' package.json solved this for me.

@methodbox
Copy link

Sounds like a problem with Webpack, not Handlebars.
The normal default path for any node module core files is /node_modules/module_name/dist.

That's where a node app will assume they are located; this means Webpack is handling require(); differently than node.

@gilesbradshaw
Copy link

I got round this with ..

resolve: {
    alias: {
       handlebars: 'handlebars/dist/handlebars.min.js'
    }
}

in my webpack config

@abhisekp
Copy link
Author

abhisekp commented Jul 1, 2016

thanks @gilesbradshaw 👍 😄

@rafde
Copy link

rafde commented Aug 27, 2016

@abhisekp was this resolved? Please close if yes.

@abhisekp
Copy link
Author

abhisekp commented Aug 27, 2016

@rafde I've not checked it but closing this issue as the issue has been made clear and a clear solution is suggested.

Thanks for the reminder. 😊

@nkonev
Copy link

nkonev commented Oct 24, 2016

issue still reproducing if I require handlebars somewhere in .js:

var Handlebars = require('handlebars');
Handlebars.registerHelper('greet', function(name) {
            return 'Hello, name=' + name + '!';
});

but if I remove this line

var Handlebars = require('handlebars');

issue is gone

@flyher
Copy link

flyher commented Nov 8, 2016

@gilesbradshaw
Thank you very much!

@oocx
Copy link

oocx commented Dec 12, 2016

I also get this error when using handlebars with an Angular 2 CLI project. I can't change my webpack configuration because the Angular CLI team decided to hide webpack details from Angular CLI users and they don't officially support modifying the webpack configuration.

@abdel-ships-it
Copy link

@oocx You could just import the JS file from the node_modules folder like so

import 'handlebars/dist/handlebars.min.js';

This works fine!

@swilliams-a3digital
Copy link

To get this to work in an angular 4 project I had to do this:
import * as handleBars from 'handlebars/dist/handlebars';

normally I'd just do this:
import * as handleBars from 'handlebars';

The line above works fine in a typescript project in node, but not in angular 4.

HandleBars is the only project where I have to import like this. It makes me concerned I'm going to have a issue down the road. It seems like HandleBars does not play nice with angular's webpack.

@nknapp
Copy link
Collaborator

nknapp commented Oct 20, 2017

I could have a look if anyone sets up a minimal example project that reproduces the issue. No promises as to the "when", though...

@JannicBeck
Copy link

@swilliams-a3digital Getting Could not find a declaration file for module declare module 'handlebars' or adding @types/handlebars does not help. How did you solve this?

@seyfer
Copy link

seyfer commented Jun 14, 2018

For others looking here

This is the best solution I have found
https://github.com/valtech-nyc/brookjs/blob/master/packages/brookjs/webpack.config.js#L39-L43
here pcardune/handlebars-loader#110 (comment)

Thanks to @mAAdhaTTah

UPD:

//fix handlebars warnings
config.resolve.alias = {
    ...config.resolve.alias,
    'handlebars/runtime': 'handlebars/dist/cjs/handlebars.runtime',
    'handlebars': 'handlebars/dist/cjs/handlebars.runtime',
};

@catamphetamine
Copy link

This is retarded.
This handlebars library should have fixed this bug.
Yet they neglect and ignore.

The workaround is to replace:

import Handlebars from 'handlebars'

with:

import Handlebars from 'handlebars/dist/cjs/handlebars'

@nknapp
Copy link
Collaborator

nknapp commented Aug 14, 2018

@catamphetamine if you have a good solution to this issue, you are welcome to file a pull request. As long as it doesn't break anything, I will merge and publish a new version. Things like const Handlebars = require('handlebars') in NodeJS and existing setups with older versions of webpack should still work.

About the "Yet they neglect and ignore":

The problem with handlebars is that there are not a lot collaborators and at the moment, as far as I can see, I am the only active one. Well, more or less active. It 23:26 now and this is the time I usually come to work on my private projects, because I have a family a daytime job and other hobbies.

So when you write "Yet they neglegt and ignore", there isn't a lot of "they". There is almost certainly no "they" that is getting paid to work on this project. I help people, because it's fun to talk to people and because it is fun to solve problems, fix bugs and write tests. Because I'm using Handlebars myself in a couple of projects, and because it feels good to stand in the stage-light from time to time. But I don't feel that it is my duty to do so. So I pick the issues that I like, mostly the ones that are quick and clear.

So, if you are using Handlebars and you have a problem and noone is going to solve it, maybe you should try to contribute a solution yourself.

I'll reopen the issue though, because it does not seem to be solved.

@nknapp nknapp reopened this Aug 14, 2018
@catamphetamine
Copy link

catamphetamine commented Aug 15, 2018

because it feels good to stand in the stage-light from time to time.

I'm doing opensource for fun too, though not as popular as this library.
And also for a line or two in my CV. Helps getting a better job.
I can see you not getting much profit out of it rather than just fun because it's not technically your project, like @nknapp/handlebars.js
You maintain it and @wycats gets all the credit and github stars as far as the URL bar goes.
Ok, at least now we know that this project is not so actively maintained anymore.
Still, it's used in many places (including legacy), I guess.
For example, SendGrid recently launched "customizable templates" using this handlebars language.
https://sendgrid.com/blog/how-to-use-sendgrids-dynamic-templates-for-your-transactional-emails/
sendgrid/sendgrid-nodejs#221

As for the possible solution, it would be splitting the package into handlebars and handlebars/register like Babel did with their babel and babel/register.
They only install the require() hook when doing import 'babel/register'.
That would be a breaking change for another major version but I can see there most likely will be no such version.
Also one could create a file in root called something like core.js (module.exports = require('handlebars/dist/cjs/handlebars')) and then Webpack users would require handlebars/core instead of handlebars/dist/cjs/handlebars (along with a line in the README).
The creator of Webpack is also from Germany.

Anyway, import Handlebars from 'handlebars/dist/cjs/handlebars' works and I think you don't need to change anything in the library, just maybe add a line of documentation to README that for Webpack use import Handlebars from 'handlebars/dist/cjs/handlebars' instead of the regular import.

By the way, I wasn't referring specifically to you because you didn't leave a negative comment before in this issue.
I was referring to @methodbox and his comment:

Sounds like a problem with Webpack, not Handlebars.

And @rafde and his comment:

Seems like a problem with your setup since nobody else has this problem

Your comment didn't claim Webpack being "wrong" or anything so no wrong words from your side:

I could have a look if anyone sets up a minimal example project that reproduces the issue. No promises as to the "when", though...

You didn't say that "Webpack is doing it wrong, close the issue" so your comments are ok.

@catamphetamine
Copy link

@nknapp
Anyway, import Handlebars from 'handlebars/dist/cjs/handlebars' works just fine and I think you don't need to change anything in the library.
Just maybe add a line to the README saying that "If you're using Webpack then import Handlebars from 'handlebars/dist/cjs/handlebars' instead of import Handlebars from 'handlebars'.
import Handlebars from 'handlebars/dist/cjs/handlebars' is fine and it works.

@camdagr8
Copy link

camdagr8 commented May 9, 2019

import Handlebars from 'handlebars/dist/cjs/handlebars

Worked for me as of this comment.

I agree with @catamphetamine though.

Better documentation is worth a lot and it wouldn't kill anyone to add that line to the installation page.

We all build great things and want people to use them.

But guess what, if the documentation sucks... so does the project because no one but you will be able to understand it.

And remember... people fear what they don't understand.

-end rant-

I do however appreciate your efforts on the library.
Being an open source dev is often a thankless and painful odyssey with very little reward.

@nknapp
Copy link
Collaborator

nknapp commented May 15, 2019

Actually, I'm not trying to make people use Handlebars. I'm just trying to help people have already decided to use it.

I am currently building a new documentation site (whenever I have some time left) and I will include it there.

@nknapp
Copy link
Collaborator

nknapp commented Apr 5, 2020

Should be resolved in #1102

@nknapp nknapp closed this as completed Apr 5, 2020
@EnnioWolsink
Copy link

This comment from @gilesbradshaw at Jul 1, 2016 is still relevant today:

I got round this with ..

resolve: {
    alias: {
       handlebars: 'handlebars/dist/handlebars.min.js'
    }
}

in my webpack config

To make this work in combination with Angular 12, I had to do the following:

  • npm i -D @angular-builders/custom-webpack
  • Make in angular.json the following changes:

From:

"build": {
  "builder": "@angular-devkit/build-angular:browser",

To:

"build": {
  "builder": "@angular-builders/custom-webpack:browser",
  ...
  "options": {
    "customWebpackConfig": {
      "path": "./custom-webpack.config.ts"
    },
    ...
  }

Note there would be other options as well. And you shouldn't literally place ... in there of course ;).

Also change this:

"serve": {
  "builder": "@angular-devkit/build-angular:dev-server",

To this:

"serve": {
  "builder": "@angular-builders/custom-webpack:dev-server",

Finally, add custom-webpack.config.ts to your project root:

import { Configuration } from 'webpack';

export default {
  resolve: {
    alias: {
       handlebars: "handlebars/dist/handlebars.min.js"
    }
  },
} as Configuration;

Be sure to check out the README of @angular-builders/custom-webpack as there might be more changes you'd need to make in angular.json and the rest of your project.

I hope this helps someone!

@Maximaximum
Copy link

Hm, strange to find out that this issue hasn't been fixed yet

@frankguo-dyedurham
Copy link

frankguo-dyedurham commented Dec 31, 2021

I am using handlebars library in a React Native project and running into the similar issue with the code:
import Handlebars from 'handlebars'

I replace it with the code below:
import Handlebars from 'handlebars/dist/handlebars'

It looks like it works now. Just try to give some other hints here for someone who runs into the issue.

BTW, import Handlebars from 'handlebars/dist/cjs/handlebars' doesn't work. I guess it is because the react native project doesn't use webpack.

@stevemk14ebr
Copy link

stevemk14ebr commented Mar 23, 2022

I get this error with webpack 5 create-react-app and I don't know why. Trying to build a simple website.

"dependencies": {
"handlebars": "^4.7.7",
}

import HandleBars from 'handlebars';

ERROR in ./node_modules/handlebars/lib/index.js 15:11-24

Module not found: Error: Can't resolve 'fs' in '/home/steve/source/repos/tmp/aster/node_modules/handlebars/lib'

the main script does this:

function extension(module, filename) {
var fs = require('fs');
var templateString = fs.readFileSync(filename, 'utf8');
module.exports = handlebars.compile(templateString);
}

how is that supposed to work with browsers?

EDIT: ok so this is a webpack 5 thing, they don't include the node polyfills anymore. And handlebars seems to be extra special and may have it's config wrong. Here's the specific webpack 5 handlebars issue which states the config is wrong: webpack/webpack#15007

and here's the wider issue about webpack 5 changing polyfill behavior. facebook/create-react-app#11756

EDIT 2: Issue webpack/webpack#15007 suggests handlebars package.json be changed to:

"browser": {
    "./lib/index.js": "./dist/cjs/handlebars.js",          /// <------ this
    "./runtime": "./dist/cjs/handlebars.runtime.js"
  },

However, this also still breaks because the dist folder doesn't exist! What is going on? I am so lost.

@jaylinski
Copy link
Member

@stevemk14ebr The dist-folder exists within the distributed npm-package.

If you want a browser-compatible version, you can try to import via import Handlebars from 'handlebars/lib/handlebars';.

You may still need to polyfill Node.js function since we didn't release the fix for #1593 yet.

@stevemk14ebr
Copy link

stevemk14ebr commented Mar 23, 2022

Yea I figured it out, I forked the repo and the git install failed since build never ran and there's no prepare script. The fix for this is:

"browser": {
    "./lib/index.js": "./dist/cjs/handlebars.js",
    "./runtime": "./dist/cjs/handlebars.runtime.js"
  },

I confirmed this works. Can you include this change?

EDIT: The import line you suggested doesn't work with webpack 5. The only workaround I have so far is to fork the lib, change the package.json browser conf as I posted, manually install the dev dependencies, build the package local, then it works. I'm going to submit a PR for the config update, if you could merge it would really great.

jaylinski added a commit that referenced this issue May 15, 2022
As explained in issue #1844 and in issue
webpack/webpack#15007 (comment),
the way we used the `browser`-field was wrong.

The main reason for using the `browser`-field is the requirement of
`require('fs')` in the main-entry-file.
The workaround for this was using `require('handlebars/lib/handlebars')`,
but now it will also work via `require('handlebars')` for bundlers that
respect the `browser`-field.

The `"./runtime"`-config was removed, because it didn't have any effect.
In order to detect regressions, the webpack-integration test was
extended to test with different webpack versions.

Fixes #1174
Closes #1844
jaylinski added a commit that referenced this issue May 15, 2022
As explained in issue #1844 and in issue
webpack/webpack#15007 (comment),
the way we used the `browser`-field was wrong.

The main reason for using the `browser`-field is the requirement of
`require('fs')` in the main-entry-file.
The workaround for this was using `require('handlebars/lib/handlebars')`,
but now it will also work via `require('handlebars')` for bundlers that
respect the `browser`-field.

The `"./runtime"`-config was removed, because it didn't have any effect.
In order to detect regressions, the webpack-integration test was
extended to test with different webpack versions.

Fixes #1174
Closes #1844
jaylinski added a commit that referenced this issue May 17, 2022
As explained in issue #1844 and in issue
webpack/webpack#15007 (comment),
the way we used the `browser`-field was wrong.

The main reason for using the `browser`-field is the requirement of
`require('fs')` in the main-entry-file.
The workaround for this was using `require('handlebars/lib/handlebars')`,
but now it will also work via `require('handlebars')` for bundlers that
respect the `browser`-field.

The `"./runtime"`-config was removed, because it didn't have any effect.
In order to detect regressions, the webpack-integration test was
extended to test with different webpack versions.

Fixes #1174
Closes #1844
jaylinski added a commit that referenced this issue May 17, 2022
As explained in issue #1844 and in issue
webpack/webpack#15007 (comment),
the way we used the `browser`-field was wrong.

The main reason for using the `browser`-field is the requirement of
`require('fs')` in the main-entry-file.
The workaround for this was using `require('handlebars/lib/handlebars')`,
but now it will also work via `require('handlebars')` for bundlers that
respect the `browser`-field.

The `"./runtime"`-config was removed, because it didn't have any effect.
In order to detect regressions, the webpack-integration test was
extended to test with different webpack versions.

Fixes #1174
Closes #1844
jaylinski added a commit that referenced this issue May 17, 2022
As explained in issue #1844 and in issue
webpack/webpack#15007 (comment),
the way we used the `browser`-field was wrong.

The main reason for using the `browser`-field is the requirement of
`require('fs')` in the main-entry-file.
The workaround for this was using `require('handlebars/lib/handlebars')`,
but now it will also work via `require('handlebars')` for bundlers that
respect the `browser`-field.

The `"./runtime"`-config was removed, because it didn't have any effect.
In order to detect regressions, the webpack-integration test was
extended to test with different webpack versions.

Fixes #1174
Closes #1844
@satyajitnayk
Copy link

I got round this with ..

resolve: {
    alias: {
       handlebars: 'handlebars/dist/handlebars.min.js'
    }
}

in my webpack config

Thanks a lot @gilesbradshaw❤️. This solution is still relevant today👍🏻.

@patricknwanah
Copy link

how do i get this handlebars.min.js file?

@patricknwanah
Copy link

I got round this with ..

resolve: {
    alias: {
       handlebars: 'handlebars/dist/handlebars.min.js'
    }
}

in my webpack config

what is handlebars/dist/handlebars.min.js. Is this the location npm installs the handlebar after you run npm install? This issue is break for me in github action and i am using rush which installs the packages in the temp folder that is ignored in the check in.

@jarpoole
Copy link

jarpoole commented Mar 4, 2024

For anyone trying to run handlebars within ts-node WITHOUT precompiling the templates (because, for example, you are using webpack's asset/source module) you can call Object.freeze(require.extensions) after you finish your setup to prevent handlebars from making further changes.

For example, running

In a new file called handlebars.js:

const fs = require('fs');

require.extensions['.hbs'] = function (module, filename) {
  const content = fs.readFileSync(filename, { encoding: 'utf-8' });
  return module._compile(
    `module.exports = ${JSON.stringify(content)}`,
    filename,
  );
};

Object.freeze(require.extensions);

Now run ts-node and require the above file:

npx ts-node -r ./handlebars.js script.ts

@nknapp I strongly agree with #1174 (comment) that the correct solution is to separate handlebars into two libs: handlebars and handlebars/register so that users can explicitly opt-in or out depending on their needs. I understand this would be a breaking change but I think it would avoid a lot of confusion going forward.

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