Execute webpack compiled bundle in NodeJS - node.js

I want to implement server-side rendering for my ReactJS app. I use react-router. I take routes.js as webpack entry point and compile with output.libraryTarget = "commonjs2" option. Then I require the result of compilation in NodeJS script to make rendering. But I've got en error.
Webpack wrap modules in following code:
/* 277 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(Buffer, global) {
if (global.foo) {
/* ... */
}
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(277).Buffer, (function() { return this; }())))
/***/ }
When NodeJS tries to execute (function() { return this; }()) its return undefined. In browser it will return window. Why webpack use such wrap code? How to make this code works in NodeJS?
I use node-clone as external lib. It don't use any other libs as dependency. But webpack in its bundle makes buffer as a dependency for this lib. And inside the buffer code I've got en error Cannot read property 'TYPED_ARRAY_SUPPORT' of undefined. It happens because in nodeJS (function() { return this; }()) return undefined.

By default, webpack will package things up for browsers. If you want to build Node libraries with webpack, you need to specifiy a target in your configuration:
module.exports = {
// ...
target: 'node',
};

Related

How does jest allow mutation of modules?

In this question that I asked here:
Why does mutating a module update the reference if calling that module from another module, but not if calling from itself?
I'm asking about the nature of module mutation.
However as it it turns out, ES6 modules can't actually be mutated - all of their properties are treated as constants. (See this answer)
But somehow - when Jest tests modules - they can be mutated, and that's how Jest allows for mocking.
How is this happening?
I imagine that it's a babel plugin that that's running - transpiling the module to CommonJS modules? Is there any documentation about this?
Is there a way to view the transpiled code?
ES6 modules can't actually be mutated - all of their properties are treated as constants.
Interesting. You're right, even something as simple as this:
import * as lib from "./lib"; // import an ES6 module
const spy = jest.spyOn(lib, 'someFunc'); // spy on someFunc
...technically shouldn't be allowed since jest.spyOn replaces the method on the object with a spy and lib.someFunc should be a binding to someFunc in the ES6 module.
But somehow - when Jest tests modules - they can be mutated, and that's how Jest allows for mocking.
How is this happening?
They can only be mutated because Jest isn't actually using ES6 modules.
(I guess for completeness it might be possible to run Jest using actual ES6 modules by using Node's experimental support for ES6 Modules but I haven't tried).
I imagine that it's a babel plugin that that's running - transpiling the module...Is there any documentation about this?
"babel-jest is automatically installed when installing Jest and will automatically transform files if a babel configuration exists in your project. To avoid this behavior, you can explicitly reset the transform configuration option".
So by default Jest will use babel-jest which transpiles the source code using babel (and does a few other things like hoisting calls to jest.mock).
Note that Jest can be also be configured using transform which maps "regular expressions to paths to transformers".
Is there a way to view the transpiled code?
Yes. Transformations are done in jest-runtime here and the output is saved to a cache here.
The easiest way to look at the transpiled code is to view the cache.
You can do that by running Jest with the --showConfig option which will output the config used when running Jest. The cache location can be found by looking at the value of "cacheDirectory".
Then run Jest with the --clearCache option to clear out the cache.
Finally, run Jest normally and the cache directory will contain the transpiled code for your project.
Example
The latest Jest (v24) will transpile this code:
// lib.js
export const someFunc = () => 1;
// code.js
import { someFunc } from './lib';
export const func = () => someFunc() + 1;
// code.test.js
import { func } from './code';
import * as lib from './lib';
test('func', () => {
const spy = jest.spyOn(lib, 'someFunc');
func();
expect(spy).toHaveBeenCalled(); // SUCCESS
});
...to this:
// lib.js
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.someFunc = void 0;
const someFunc = () => 1;
exports.someFunc = someFunc;
// code.js
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.func = void 0;
var _lib = require("./lib");
const func = () => (0, _lib.someFunc)() + 1;
exports.func = func;
// code.test.js
"use strict";
var _code = require("./code");
var lib = _interopRequireWildcard(require("./lib"));
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
test('func', () => {
const spy = jest.spyOn(lib, 'someFunc');
(0, _code.func)();
expect(spy).toHaveBeenCalled(); // SUCCESS
});
The import * as lib from 'lib'; line gets handled by _interopRequireWildcard which uses require under the hood.
Every call to require "will get exactly the same object returned, if it would resolve to the same file" so code.js and code.test.js are getting the same object from require('./lib').
someFunc is exported as exports.someFunc which allows it to be reassigned.
So yes, you're exactly right. Spying (or mocking) like this only works because the ES6 modules are getting transpiled by babel into Node modules in a way that allows them to be mutated.

node + requirejs: module is not defined

Getting a module is not defined error attempting to import a module from the local project. Using node and requirejs -
Error: Evaluating /Users/Projects/stash/NODE/project_js/src/foo.js as module "foo" failed with error: ReferenceError: module is not defined
Code looks like -
(function() {
const requirejs = require('requirejs')
requirejs.config({
baseUrl: __dirname,
nodeRequire:require
});
//var foo = requirejs('foo.js');
requirejs(['foo'], function() {
foo().then(data => {
data.foreach(function(item, index, data) {
console.log(JSON.stringify(item))
})
});
})
})();
The module has the following export -
module.exports = function foo() {
.
.
.
return results
}
I've tried loading the module synchronously as well.
Check this part of their doc: if the module to be loaded (foo here) is found by RequireJS (i.e. its configuration allows it to find the module), then this module has to be declared using define instead of Node's exports.
I just tried this, which works:
directory structure
test/
index.js
foo.js
index.js
(function() {
const requirejs = require('requirejs');
requirejs.config({
baseUrl: __dirname,
nodeRequire:require
});
requirejs(['foo'], (foo) => {
console.log('loaded!', foo, foo());
});
})();
foo.js (that's the interesting part)
define(function() {
return function foo() {
return 'fooResult';
}
});
Using module.exports = ... gave me the error you have.
However this RequireJS API is not "loadable" by Node's built-in require, hence the need for a precise configuration that reflects a clear separation between Node-required modules (CommonJS API) and RequireJS-defined modules (AMD API). (Actually you can check the whole "Why AMD?" page, that should help a lot for your work with RequireJS.)

Gulp + Browserify + TypeScript To Browser

My problem is the following:
I use gulp+browserify to compile my TypeScript to JavaScript that you can use on normal HTML pages, the problem is that my class is never available on the browser:
VM633:1 Uncaught ReferenceError: Test is not defined
at <anonymous>:1:13
This is my TypeScript File:
class Test {
public test(): void {
console.log("aa");
}
}
This is my gulpfile
var gulp = require("gulp");
var browserify = require("browserify");
var source = require('vinyl-source-stream');
var tsify = require("tsify");
gulp.task("default", function () {
return browserify({
//basedir: '.',
debug: true,
entries: ['app/Resources/typescript/Test.ts'],
cache: {},
packageCache: {}
})
.plugin(tsify)
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest("web/bundles/framework/js"));
});
The file compiles without problem, and is included in my index.html (the compiled js file).
But when i try:
var t = new Test();
I get the following error:
VM633:1 Uncaught ReferenceError: Test is not defined
at <anonymous>:1:13
I can't resolve it, I have read a lot and I haven't found anything clear, I tried all and nothing worked.
There are a few things missing here:
If you want your class to be accessible outside of your module, you have to export it:
export class Test {
// ...
}
Browserify creates functions on top of the classes you define. So it won't be accessible globally (which is a good thing). Normally you would import it in another file and use it:
// in any TS file that wants to use `Test` class. Make sure this is included in the gulp entries as well
import {Test} from "test";
var t = new Test();
console.log(t);
Or if really want it to be accessible globally, you can attach it to window object:
// In Test.ts file:
(window as any).Test = Test; // This can be useful when debuging. But don't do this in production code.

Best practice for minifying TypeScript modules

I'm using requirejs and AMD modules for my TypeScript project, with something like 20 different source files at the moment and likely to grow substantially. All of this works, but it's very slow to load all 20 files, so it would be better to have them minified. But because of how requirejs wants to load everything, it seems like it's going to require that I keep the modules in separate files - I don't think I can just take the generated module1.js and module2.js files and minify them into one file and then have requirejs load those without changing some code. (I could be wrong on this.)
The other way that I see to do this is to use the r.js file that requirejs provides to merge all the different files together in a way that still keeps requirejs happy. But r.js requires node.js, and I'd rather not introduce that as a dependency in my build process if there's any other way to do it.
So before I dive into this and try half a dozen different solutions - how are other folks approaching this with big projects?
What you could do is to implement a thin RequireJS shim to use in a minified build. Depending on how much of the RequireJS API you want to use, you could get by with very little. For simplicity you could also use named modules.
Say, while developing you use RequireJS to load your modules. When you want to make a minified build, you could simply include a simple loader in the minified file.
If you have files app.js, foo.js and bar.js as follows:
//from app.js
define("app", ["foo", "bar"], function(foo, bar) {
return {
run: function() { alert(foo + bar); }
}
});
//from foo.js
define("foo", [], function() {
return "Hello ";
});
//from bar.js
define("bar", [], function() {
return "World!";
});
And let's say you minify all those files together. At the top of the file you include the following shim:
//from your-require-shim.js
(function(exports) {
var modules = {};
var define = function(name, dependencies, func) {
modules[name] = {
name:name,
dependencies:dependencies,
func:func,
result:undefined
};
};
var require = function(name) {
var module = modules[name];
//if we have cached result -> return
if(module.result) { return module.result; }
var deps = [];
//resolve all dependencies
for(var i=0,len=module.dependencies.length;i<len;i++) {
var depName = module.dependencies[i];
var dep = modules[depName];
if(!dep.result) {
//resolve dependency
require(depName);
}
deps.push(dep.result);
}
module.result = module.func.apply(this, deps );
return module.result;
};
exports.require = require;
exports.define = define;
}(window));
And execute the module defined in app.js
require("app").run();
Like in this fiddle.
It's a crude PoC of course, but I'm sure you get the meaning.
If you are using ASP.NET MVC 4, you can make a bundle which will minify everything when you deploy to production in a set of files or in a folder. You'll find more info on bundles here.

Problems loading i18next.js with require.js

I'm pretty new to require.js and having problems loading i18next.js.
main.js
require(["lib/jquery", "lib/i18next", "config.i18next", "constants"],
function(util) {
console.log("loaded javascript files");
});
and config.i18next.js
var option = {resGetPath: '../translations/__lng__.json' };
i18n.init(option, function(t) {
console.log("Language initialization successfull");
});
I always get the error
Uncaught ReferenceError: i18n is not defined config.i18next.js:2
I know who to use i18next, and everything works fine when loading the javascript files traditionally.
EDIT:
Meanwhile I got it working with shim like this:
requirejs.config({
shim: {
'lib/i18next' : ['lib/jquery'],
}
});
require(["lib/i18next"], function(i18n) {
var options = {
resGetPath: 'translations/__lng__.json',
preload: ['de', 'en']
};
i18n.init(options, function(t) {
});
});
and I can translate in other files with $.t("key"); , but when now I can't change the language programatically with i18n.setLng() because the variable can't be found ReferenceError: Can't find variable: i18n.
--- i18next comes now with amd build ---
this should solve all issues using i18next with amd. you can grab it at http://i18next.com

Resources