helpers / handlebars-helpers

188 handlebars helpers in ~20 categories. Can be used with Assemble, Ghost, YUI, express.js etc.
http://assemble.io/helpers/
MIT License
2.22k stars 364 forks source link

Error including module with webpack #324

Closed flyingL123 closed 6 years ago

flyingL123 commented 6 years ago

I am simply importing the library into my webpack project, but am receiving an error. I'm not even actually using the library, just importing it like this:

import helpers from 'handlebars-helpers';

When webpack bundles my files, I get the following error:

Module not found: Error: Can't resolve 'fs' in '/Users/me/dev/project/node_modules/handlebars-helpers/lib' resolve 'fs' in '/Users/me/dev/project/node_modules/handlebars-helpers/lib'
  Parsed request is a module
  using description file: /Users/me/dev/project/node_modules/handlebars-helpers/package.json (relative path: ./lib)
    Field 'browser' doesn't contain a valid alias configuration
  after using description file: /Users/me/dev/project/node_modules/handlebars-helpers/package.json (relative path: ./lib)
    resolve as module
      /Users/me/dev/project/node_modules/handlebars-helpers/lib/node_modules doesn't exist or is not a directory
      /Users/me/dev/project/node_modules/node_modules doesn't exist or is not a directory
      /Users/me/dev/node_modules doesn't exist or is not a directory
      /Users/me/node_modules doesn't exist or is not a directory
      /Users/node_modules doesn't exist or is not a directory
      /node_modules doesn't exist or is not a directory
      looking for modules in /Users/me/dev/project/node_modules/handlebars-helpers/node_modules
        using description file: /Users/me/dev/project/node_modules/handlebars-helpers/package.json (relative path: ./node_modules)
          Field 'browser' doesn't contain a valid alias configuration
        after using description file: /Users/me/dev/project/node_modules/handlebars-helpers/package.json (relative path: ./node_modules)
          using description file: /Users/me/dev/project/node_modules/handlebars-helpers/package.json (relative path: ./node_modules/fs)
            no extension
              Field 'browser' doesn't contain a valid alias configuration
              /Users/me/dev/project/node_modules/handlebars-helpers/node_modules/fs doesn't exist
            .js
              Field 'browser' doesn't contain a valid alias configuration
              /Users/me/dev/project/node_modules/handlebars-helpers/node_modules/fs.js doesn't exist
            .json
              Field 'browser' doesn't contain a valid alias configuration
              /Users/me/dev/project/node_modules/handlebars-helpers/node_modules/fs.json doesn't exist
            as directory
              /Users/me/dev/project/node_modules/handlebars-helpers/node_modules/fs doesn't exist
      looking for modules in /Users/me/dev/project/node_modules
        using description file: /Users/me/dev/project/package.json (relative path: ./node_modules)
          Field 'browser' doesn't contain a valid alias configuration
        after using description file: /Users/me/dev/project/package.json (relative path: ./node_modules)
          using description file: /Users/me/dev/project/package.json (relative path: ./node_modules/fs)
            no extension
              Field 'browser' doesn't contain a valid alias configuration
              /Users/me/dev/project/node_modules/fs doesn't exist
            .js
              Field 'browser' doesn't contain a valid alias configuration
              /Users/me/dev/project/node_modules/fs.js doesn't exist
            .json
              Field 'browser' doesn't contain a valid alias configuration
              /Users/me/dev/project/node_modules/fs.json doesn't exist
            as directory
              /Users/me/dev/project/node_modules/fs doesn't exist

If I remove the import statement, the error goes away. Am I missing something obvious here or is there a bug in the library?

I'm using Node v7.9.0, webpack version 3.12.0, and handlebars-helpers version 0.10.0.

doowb commented 6 years ago

@flyingL123 are you able to show your webpack config file? Or better yet, show an example repository of this happening?

flyingL123 commented 6 years ago

Thanks @doowb here is webpack config:

var CleanWebpackPlugin = require('clean-webpack-plugin'),
    config = require('./config.json'),
    LodashModuleReplacementPlugin = require('lodash-webpack-plugin'),
    path = require('path'),
    webpack = require('webpack');

module.exports = {
    bail: true,
    context: __dirname,
    devtool: 'source-map',
    entry: {
        main: './assets/js/app.js',
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                include: /(assets\/js|assets\\js|node_modules\/@bigcommerce\/stencil-utils|node_modules\\@bigcommerce\\stencil-utils|node_modules\/foundation-sites\/js|node_modules\\foundation-sites\\js)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        cacheDirectory: true,
                        compact: true,
                        minified: true,
                        plugins: [
                            'dynamic-import-webpack', // Needed for dynamic imports.
                            'lodash', // Automagically tree-shakes lodash.
                            'transform-regenerator', // Transforms async and generator functions.
                        ],
                        presets: [
                            ['env', {
                                loose: true, // Enable "loose" transformations for any plugins in this preset that allow them.
                                modules: false, // Don't transform modules; needed for tree-shaking.
                                useBuiltIns: true, // Tree-shake babel-polyfill.
                            }],
                        ],
                    }
                }
            }
        ],
    },
    output: {
        chunkFilename: 'theme-bundle.chunk.[name].js',
        filename: 'theme-bundle.[name].js',
        path: path.resolve(__dirname, "assets/dist"),
    },
    plugins: [
        new CleanWebpackPlugin(['assets/dist'], {
            verbose: true,
            watch: false,
        }),
        new webpack.LoaderOptionsPlugin({
             minimize: true,
        }),
        new LodashModuleReplacementPlugin, // Complements 'babel-plugin-lodash by shrinking it's cherry-picked builds further.
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery',
            'window.jQuery': 'jquery',
        }),
        new webpack.optimize.CommonsChunkPlugin({
            children: true,
            minChunks: 2,
        }),
    ],
    resolve: {
        alias: {
            jquery: path.resolve(__dirname, 'node_modules/jquery/dist/jquery.min.js'),
            jstree: path.resolve(__dirname, 'node_modules/jstree/dist/jstree.min.js'),
        },
    },
    watch: false,
};
doowb commented 6 years ago

One thing you might be able to try is adding fs to the resolve.alias object:

resolve: {
  alias: {
    fs: false
  }
}

I'm trying to see if there's anything else that may need to be configured. I've done this using browserify but never with webpack.

doowb commented 6 years ago

@flyingL123 here's a similar issue... maybe the same issue.

flyingL123 commented 6 years ago

Hmm it doesn't like that:

WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
 - configuration.resolve.alias should be one of these:
   object { <key>: string } | [object { alias?, name?, onlyModule? }]
   -> Redirect module requests
   Details:
    * configuration.resolve.alias['fs'] should be a string.
      -> New request
    * configuration.resolve.alias should be an array:
      [object { alias?, name?, onlyModule? }]
doowb commented 6 years ago

I guess there's another place where that would go. I'm not that familiar with webpack and thought that would be the correct setting.

flyingL123 commented 6 years ago

I did look through https://github.com/helpers/handlebars-helpers/issues/263 earlier. I'll give it another try now.

flyingL123 commented 6 years ago

I don't know. This didn't fix anything for me either. This is really a frustrating one.

doowb commented 6 years ago

I agree... I'm trying to put together an example webpack configuration that works. I'll try to get that done this evening.

flyingL123 commented 6 years ago

Thanks so much! That would be an enormous help.

doowb commented 6 years ago

@flyingL123 I got it working with the following webpack.config.js:

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  resolve: {
    alias: {
     handlebars: 'handlebars/dist/handlebars.min.js'
    }
  },
  node: {
    fs: 'empty',
    readline: 'empty'
  }
};

and the src/index.js looks like this:

import handlebars from 'handlebars';
import helpers from 'handlebars-helpers';

function component(name) {
  handlebars.registerHelper(helpers());

  var element = document.createElement('div');
  element.innerHTML = handlebars.compile('<button>{{capitalize name}}</button>')({ name });
  return element;
}

document.body.appendChild(component('doowb'));

This comment from @spplante helped a lot.

flyingL123 commented 6 years ago

@doowb did you have to do anything with unlazy-loader, like what's mentioned in https://github.com/helpers/handlebars-helpers/issues/261#issuecomment-296526808?

Using your config stops the error. However, now when the browser loads, I get an error on line 3 of node_modules/handlebars-helpers/lib/utils/utils.js that says:

Uncaught Error: Cannot find module "."

When I remove the handlebars-helpers import, the error goes away.

Is it possible that there is some compatibility issue with webpack's code splitting? You can see in the original config file I posted that I'm using the CommonsChunkPlugin. I have no idea why that would matter but I'm just trying to find any difference between your working example and mine.

doowb commented 6 years ago

I didn't get an error so I didn't try using unlazy-loader, but after looking utils/utils.js file that you mentioned, lazy-cache is being used so you'll need to use unlazy-loader. I'm don't know how the CommonsChunkPlugin works or if it would be causing an issue.

flyingL123 commented 6 years ago

Thanks so much for your help. Using unlazy-loader changes the error to line 47 of node_modules/ansi-colors/index.js:

Uncaught TypeError: require is not a function

Any idea what would cause that?

flyingL123 commented 6 years ago

I wonder if it has something to do with this:

/**
 * Temporarily re-assign `require` to trick browserify and
 * webpack into reconizing lazy dependencies.
 *
 * This tiny bit of ugliness has the huge dual advantage of
 * only loading modules that are actually called at some
 * point in the lifecycle of the application, whilst also
 * allowing browserify and webpack to find modules that
 * are depended on but never actually called.
 */

var fn = require;
require = colors;
doowb commented 6 years ago

That's what unlazy-loader is for.

doowb commented 6 years ago

@flyingL123 it looks like the version of ansi-colors that's in the dependency tree is using a pattern (actually variable names) that unlazy-loader doesn't expect. I'll try to get a patch to unlazy-loader published with the necessary changes to handle it, but it might be a little bit.

Thanks for the patience and all the information you're providing.

doowb commented 6 years ago

@flyingL123 I published a patch to unlazy-loader, but there's still an issue with log-utils. I was looking for a way to just exclude the module like you can do with fs, but it doesn't seem like alias will let me do false or 'empty'.

flyingL123 commented 6 years ago

What about using something like module.noParse or Rule.exclude to ignore the log-utils files? I don't fully understand the issue so I'm not even sure if that would help.

Or, I remember seeing this null-loader and wondering what it would ever be used for. Maybe this is it?

flyingL123 commented 6 years ago

Ah whoops, just realized the null-loader requires at least webpack 4. I'm pretty sure uprgrading to 4 fixes the issue anyway, so the loader wouldn't be needed. Upgrading to 4 causes some new issues within my project so I'm hoping to keep webpack where it is and just get this working. I'm still experimenting over here.

doowb commented 6 years ago

I'm pretty sure uprgrading to 4 fixes the issue anyway, so the loader wouldn't be needed.

This is probably why it worked for me without the unlazy-loader. I don't use webpack so I just started on their "Getting Started" page and installed the latest version.

flyingL123 commented 6 years ago

Yup, I just updated my project to webpack 4 and there are no issues. I didn't need unlazy-loader.

However, I am now finding that after importing handlebars-helpers, my main bundle chunk is output as 7.5 MB. Without handlebars-helpers it's 4.2 MB. I realize I'm getting off topic here, but is it expected that importing the library adds so much size?

doowb commented 6 years ago

Yup, I just updated my project to webpack 4 and there are no issues.

Awesome!

When bundling handlebars and handlebars-helpers only, I've usually seen the size be around 1 - 1.2MB, so there might be a configuration setting or plugin for reducing that.

I'm going to close this issue since bundling is working with the latest webpack. I'll be opening an issue on log-utils to remind myself (or anyone else) to update it based on what we've found here.