Raghu Raghu - 2 months ago 25
Javascript Question

WebPack and Require

I have a module A as follows,Module A is bundles using web pack and it includes Module B. This module also exports Highcharts library using require variable

A.js (under modules folder:: src/main/webapp/resources/js/modules)

var HighCharts = require("highchart");
var moduleB = require("../common/B.js"); //so that we can call draw() of moduleB

$(document).ready(function() {
moduleB.print();
}


B.js (Under Common Folder: src/main/webapp/resources/js/common)

var print = function() {
console.log("something");
draw();
}
var chart;
function draw() {
chart = new Highcharts.Chart({

});
}

exports.print = print;


Note ModuleB.js is bundled in A.js

When i load the javascript, it is throwing me an error, Highcharts is undefined.

//how to load this

chart = new Highcharts.Chart({

});


To avoid this error, I did the following.

In B.js did the following.

var Highcharts = require('highcharts');

Also moved B.js into modules folder from common folder, as it is an Entry Point Now(moved to src/main/webapp/resources/js/modules from src/main/webapp/resources/js/common)

WebPack is giving me the following error.

ERROR in ./src/main/webapp/resources/js/modules/A.js Module not found: Error: a dependency to an entry point is not allowed
@ ./src/main/webapp/resources/js/modules/A.js 7:14-37

Webpack.config.js

Entry point will be all the files under the modules folder.

var path = require('path');
var webpack = require("webpack");
var glob = require("glob");
//var BowerWebpackPlugin = require("bower-webpack-plugin");
var jsSrcPath = 'src/main/webapp/resources/js/modules/**/*.js';
var jsDestPath = 'src/main/webapp/resources/build/js/modules';
var cssPath = '';


var files = glob.sync(jsSrcPath, {});
var entries = {};


for (var i = 0; i < files.length; i++) {
var file = files[i];
entries[file.replace(/^.*[\\\/]/, '').replace(/\.[^/.]+$/, "")] = path.join(__dirname, file);
}

var webpackOptions = {
cache: true,
watch: false,
entry: entries,
output: {
path: __dirname + "/" + jsDestPath,
filename: '[name].js',
},
module: {
loaders: [{
test: /.(?:jsx|js)$/,
exclude: /node_modules/,
loader: 'babel-loader?blacklist=useStrict'
},
// }, {
// test: /\.json/,
// exclude: /node_modules/,
// loader: 'json-loader'
// }, {
// test: /\.css$/,
// exclude: /node_modules/,
// loader: "style!css"
// }, {
// test: /\.scss$/,
// exclude: /node_modules/,
// loader: 'style-loader!css-loader!sass-loader!autoprefixer-loader?browsers=last 10 version'
// }, {
// test: /\.(png|jpg)$/,
// exclude: /node_modules/,
// loader: 'url-loader?limit=999999'
// }, {
{
test: /vendor\/.+\.(jsx|js)$/,
exclude: /node_modules/,
loader: 'imports?jQuery=jquery,$=jquery,this=>window'
}
]
},
resolve: {
root: [path.join(__dirname, "bower_components")],
extensions: ['', '.js', '.json', '.jsx', '.css']
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
}),
// new webpack.optimize.UglifyJsPlugin({
// compress: {
// warnings: false
// }
// })
],
devServer: {
contentBase: ".",
noInfo: true, // --no-info option
hot: true,
inline: true
}
};



module.exports = webpackOptions;


PS: Initially B.js is outside modules folder as it is not an entry point. Later it was moved inside modules folder, as we have made that as an entry point.

Answer

"Clearly i don't want to load my highchairs lib in moduleB as it is not an entry point for web pack"

This is actually not the case, as unintuitive as it may seem! You do need to import Highcharts in moduleB, as that's where you're using it. In Node and Webpack, module imports aren't global; if you had a moduleC with another chart in it, you'd have to import Highcharts there too.

Webpack is smart enough to not run/include the imported code twice, so there's no reason to avoid doing this. This answer I wrote a while back explains exactly how this works.

EDIT: Looking at your config, I think you may have the wrong idea about how Webpack works. You don't input a whole directory of files and then get an entire directory full of files back; you set a single file as the entry point, and then Webpack traces all of its dependencies, bundling everything into a single output file*. The entry point is, as the name suggests, the point where you enter into your application - you definitely shouldn't be setting every file in your source folder as an entry point like you are now!

Here is a (hopefully) fixed version of your config:

var path = require('path');
var webpack = require("webpack");
var jsDestPath = 'src/main/webapp/resources/build/js/modules';
var cssPath = '';

var webpackOptions = {
  cache: true,
  watch: false,
  entry: path.join(__dirname, "src/main/webapp/resources/js/modules/a.js"),
  output: {
    path: __dirname + "/" + jsDestPath,
    filename: '[name].js',
  },
  module: {
    loaders: [{
        test: /.(?:jsx|js)$/,
        exclude: /node_modules/,
        loader: 'babel-loader?blacklist=useStrict'
      },
      // }, {
      //   test: /\.json/,
      //   exclude: /node_modules/,
      //   loader: 'json-loader'
      // }, {
      //   test: /\.css$/,
      //   exclude: /node_modules/,
      //   loader: "style!css"
      // }, {
      //   test: /\.scss$/,
      //   exclude: /node_modules/,
      //   loader: 'style-loader!css-loader!sass-loader!autoprefixer-loader?browsers=last 10 version'
      // }, {
      //   test: /\.(png|jpg)$/,
      //   exclude: /node_modules/,
      //   loader: 'url-loader?limit=999999'
      // }, {
      {
        test: /vendor\/.+\.(jsx|js)$/,
        exclude: /node_modules/,
        loader: 'imports?jQuery=jquery,$=jquery,this=>window'
      }
    ]
  },
  resolve: {
    root: [path.join(__dirname, "bower_components")],
    extensions: ['', '.js', '.json', '.jsx', '.css']
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery"
    }),
    // new webpack.optimize.UglifyJsPlugin({
    //   compress: {
    //     warnings: false
    //   }
    // })
  ],
  devServer: {
    contentBase: ".",
    noInfo: true, //  --no-info option
    hot: true,
    inline: true
  }
};



module.exports = webpackOptions;

* This is a generalization - you can have multiple entry points, but they need to be independent - they definitely can't import each other.`