0

I'm trying to refactor client javascript in my nodejs/express application using CommonJS + Webpack modules.

With Webpack I build a 'bundle.js' made of two js files where I defined the two modules following CommongJS syntax. But on window.onload of the page I get a nice 'TypeError: moveTo.logHelloWorld is not a function" error.

Where am I wrong?

Webpack configuration:

var webpack = require('webpack');
var path = require('path');

module.exports = {
  entry: ['./public/js/common.js', './public/js/moveTo.js'],
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'bundle.min.js'
  },
  plugins: process.env.NODE_ENV === 'production' ? [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin()
  ] : []
}

moveTo.js

var moveTo = {};

console.log("moveTo.js loaded...");

moveTo.logHelloWorld = function(){
  console.console.log("Hello World logHelloWorld() from moveTo client Javascript!");
};

module.exports = moveTo;

moveTo.handlebars

<div>MoveTo</div>
<script type="text/javascript">
  window.onload = function(){
    console.log("ON LOAD...");
    moveTo.logHelloWorld();
  }
</script>

and finally in the main template I included the bundle.js built with Webpack:

<script src="/bundle.min.js" type="text/javascript"></script>

And this is the error I got:

enter image description here

UPDATE: How to use multiple client js files Suppose I would like to add another test.js file with its own module like so:

test.js

var test = {};

console.log("test.js loaded...");

test.logHelloWorld = function(){
  console.log("Hello World logHelloWorld() from TEST client Javascript!");
};

module.exports = test;

And then in Webpack config:

var webpack = require('webpack');
var path = require('path');

module.exports = {
  entry: ['./public/js/common.js', './public/js/moveTo.js', './public/js/test.js'],
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'bundle.min.js',
    library: ["moveTo", "test"] //This is not working.
  },
  plugins: process.env.NODE_ENV === 'production' ? [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin()
  ] : []
}

How may I get this to work?

UPDATE: This is what i get using the suggested webpack configuration enter image description here

#LAST UPDATE#

Apparently there is no way to have a single bundle.js and get it to work with different javascript files. This is the only thing I reached so far with the precious help of @hazardous:

webpack.config.js

var webpack = require('webpack');
var path = require('path');
// ['./public/js/common.js', './public/js/moveTo.js', './public/js/test.js'],
module.exports = {
  entry: './public/js/t3toolbox.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'bundle.min.js',
    library: ["t3toolbox", "[name]"]
  },
  plugins: process.env.NODE_ENV === 'production' ? [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin()
  ] : []
}

t3toolbox.js

var t3toolbox = {}; // Global App NameSpace
var test = require('./test.js');
var moveTo = require('./moveTo.js');

t3toolbox.moveTo = moveTo;
t3toolbox.test = test;

module.exports = t3toolbox;

moveTo.js

var moveTo = {};

console.log("moveTo.js loaded...");

moveTo.logHelloWorld = function(){
  console.log("Hello World logHelloWorld() from MOVETO client Javascript!");
};

module.exports = moveTo;

test.js

var test = {};

console.log("test.js loaded...");

test.logHelloWorld = function(){
  console.log("Hello World logHelloWorld() from TEST client Javascript!");
};

module.exports = test;

moveTo.handlebars

moveTo
<script type="text/javascript">
  window.onload = function(){
    console.log("ON LOAD...");
    t3toolbox.main.moveTo.logHelloWorld();
    t3toolbox.main.test.logHelloWorld();
  }
</script>

As you can see you still have to use the main after t3toolbox. I never accomplished the configuration where you end up with

var mylibrary = {
  moveTO: {/*...*/},
  test: {/*...*/}
}

It always end up with:

var mylibrary = {
  main: {
    moveTo: {/*...*/},
    test: {/*...*/}
  }
}
7
  • Where is the script tag added? Commented May 12, 2017 at 9:30
  • Do you mean the last one with bundle.js? This script tag is included in the main.handlebars layout of the application. If you instead refer to the one where I call the moveTo.logHelloWorld() function, that tag is added to the end of the moveTo.handlebars template that refers to the page where I would like to call the function mentioned. Commented May 12, 2017 at 9:32
  • Try by adding this script tag inside header Commented May 12, 2017 at 9:42
  • From the webpack config snippet, it is not clear what is the libraryTarget configured to. If its not there, webpack uses the var option, but that needs library.name to be defined as well. Please share the complete webpack config, if possible. Commented May 12, 2017 at 9:42
  • @hazardous I added the complete webpack configuration file. Commented May 12, 2017 at 9:43

1 Answer 1

1

Try adding library to output configuration, like so -

var webpack = require('webpack');
var path = require('path');

module.exports = {
  entry: ['./public/js/common.js', './public/js/moveTo.js'],
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'bundle.min.js',
    library: 'moveTo'
  },
  plugins: process.env.NODE_ENV === 'production' ? [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin()
  ] : []
}

If your library has several exported entities, use this -

var webpack = require('webpack');
var path = require('path');

module.exports = {
  entry: ['./public/js/common.js', './public/js/moveTo.js'],
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'bundle.min.js',
    library: ["mylibrary", "[name]"]
  },
  plugins: process.env.NODE_ENV === 'production' ? [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin()
  ] : []
}

This example is based on https://github.com/webpack/webpack/blob/master/examples/multi-part-library/webpack.config.js#L10.

This example configuration will create an export of this form:

var mylibrary : {
    "common": {/* exports from common */},
    "moveTo": {/* exports from moveTo */}
}

So you can use them in your code using mylibrary.common, mylibrary.moveTo etc.

If you don't want to club all of your imports in "mylibrary", you can change the library to -

library:"[name]"

This will create separate var moveTo = ... and var test = ... exports.

Sign up to request clarification or add additional context in comments.

7 Comments

It works!! Thank you! But what if I would like to add another module to the list, to be called in another page? Should I use an array for the library configuration?
Updated the answer to support multi-export lib. Also, please accept the answer if it solved the issue. Thanks.
In library: ["mylibrary", "[name]"], "[name]" should be kept as it is, do not replace it with test :). It is a special placeholder which is replaced by the name of the entry. So once you fix this, the output library will be of this shape - mylibrary:{"common":..., "moveTo":..., "test" : ...}. Hope this is less confusing now :).
Updated my example with usage info.
I changed as you said leaving the ["mylibrary", "[name]"] string as it is, but the mylibrary has only a main key with only the function from the test.js file. More on the updated question.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.