How can I configure options using the traceur module on nodejs - node.js

How do I configure options using the traceur module on nodejs. I'm doing the following but it doesn't seem to work.
require('traceur').require.makeDefault(function(filename) {
// don't transpile our dependencies, just our app
return filename.indexOf('node_modules') === -1;
});
traceur.options.annotations = true;
require('./start.js');
traceur.options.annotations = true is not resulting in annotations being enabled in traceur

Pass the options as the second argument to makeDefault:
require('traceur').require.makeDefault(function(filename) {
// don't transpile our dependencies, just our app
return filename.indexOf('node_modules') === -1;
}, {annotations: true});
See https://github.com/google/traceur-compiler/blob/master/src/node/require.js#L58
You need to update use this feature.

Related

In Node v8 (v8.9.3 or above), commonjs require module create new context

We are working on templating library with helpers (Dust.js), the helper library has below design pattern inside the codebase.
(function(root, factory) {
if (typeof define === 'function' && define.amd && define.amd.dust === true) {
define(['dust-linkedin'], factory);
} else if (typeof exports === 'object') {
module.exports = factory(require('dust-linkedin'));
// module.exports = factory; // <<--- This is working on v8
} else {
factory(root.dust);
}
}(this, function (dust) {
...
});
In node v6, exporting factory(require('dust-linkedin')) is working fine, but after switching to node v8 (v8.9.3) and we see helpers are not getting executed, changing factory(require('dust-linkedin')) to factory inside the helper library, things starts working.
In node v8, when require('dust-linkedin') does it create a new context/object because of which we are losing all our helpers? Is there any change in commonjs require behavior?
The solution was fixed in the PR https://github.com/krakenjs/festucam/pull/4

How can I make a npm module avaible in browser

I made a npm module, it works perfectly in node, but I laso want to make it avaible in browser as Socket.io is. In node I use it that way : var AIM = require('aimjs')(server)
server param is optional and is from http.Server (Node.js doc) if specified it serve a client version of the module as Socket.io do :
if (this.server != null) {
var listeners = this.server.listeners('request').slice()
this.server.removeAllListeners('request')
this.server.on('request', function (req, res) {
if (url.parse(req.url).pathname === '/AIM.js') {
res.setHeader('Content-Type', 'application/javascript')
res.writeHead(200)
res.end(fs.readFileSync(__dirname + '/AIM.client.js'))
} else {
for (var i = 0; i < listeners.length; i++) {
listeners[i].call(self.srv, req, res)
}
}
})
}
This file (AIM.client.js) is a browserified version of my main, but the module is not avaible outside. How can I make it global ? I want that users just have to install module, include <script type='text/javascript' src='/AIM.js'></script> and can use it both client side and server side.
When you browserify your file, use the --standalone (-s) option.
Example:
browserify index.js -s aimjs
This will make your file a UMD bundle.
If it is used in a CommonJS environment, it will behave as a CommonJS module.
If it is used in an AMD environment, it will behave as an AMD module.
If it is simply included via a script tag, it will attach itself to window.aimjs.

Execute webpack compiled bundle in NodeJS

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',
};

Browserify + browserify-ngannotate + Tsify not working

I'm using gulp with browserify and tsify. This has been working quite well. Then I decided to add ng-annotate using browserify-ngannotate.
I've added the ng-annotate browserify transform but it seems that if tsify is added as a plugin the ng-annotate transform is never called.
If I remove the tsify plugin then ng-annote gets called. I've played around and switched around the plugin/transform registration. Am I missing something here, or should I go and log an issue at browserify/tsify?
var browserify = require('browserify');
var browserSyncConfig = require('../config').browserSync;
var browserSync = require('browser-sync').get(browserSyncConfig.instance);
var watchify = require('watchify');
var tsify = require('tsify');
var ngAnnotate = require('browserify-ngannotate');
var mergeStream = require('merge-stream');
var bundleLogger = require('../util/bundleLogger');
var gulp = require('gulp');
var handleErrors = require('../util/handleErrors');
var source = require('vinyl-source-stream');
var config = require('../config').browserify;
var _ = require('lodash');
var browserifyTask = function (devMode) {
var browserifyThis = function (bundleConfig) {
if (devMode) {
// Add watchify args and debug (sourcemaps) option
_.extend(bundleConfig, watchify.args, {debug: true});
// A watchify require/external bug that prevents proper recompiling,
// so (for now) we'll ignore these options during development. Running
// `gulp browserify` directly will properly require and externalize.
bundleConfig = _.omit(bundleConfig, ['external', 'require']);
}
var b = browserify(bundleConfig);
if (bundleConfig.tsify) {
b = b.plugin(tsify, {
noImplicitAny: false,
target: 'ES5',
noExternalResolve: false,
module: 'commonjs',
removeComments: false
});
}
if (bundleConfig.ngAnnotate) {
b = b.transform(ngAnnotate);
}
var bundle = function () {
// Log when bundling starts
bundleLogger.start(bundleConfig.outputName);
return b
.bundle()
// Report compile errors
.on('error', handleErrors)
// Use vinyl-source-stream to make the
// stream gulp compatible. Specify the
// desired output filename here.
.pipe(source(bundleConfig.outputName))
// Specify the output destination
.pipe(gulp.dest(bundleConfig.dest))
.pipe(browserSync.stream());
};
if (devMode) {
// Wrap with watchify and rebundle on changes
b = watchify(b, {
poll: true
});
// Rebundle on update
b.on('update', bundle);
bundleLogger.watch(bundleConfig.outputName);
} else {
// Sort out shared dependencies.
// b.require exposes modules externally
if (bundleConfig.require) b.require(bundleConfig.require);
// b.external excludes modules from the bundle, and expects
// they'll be available externally
if (bundleConfig.external) b.external(bundleConfig.external);
}
return bundle();
};
// Start bundling with Browserify for each bundleConfig specified
return mergeStream.apply(gulp, _.map(config.bundleConfigs, browserifyThis));
};
gulp.task('browserify', function () {
return browserifyTask()
});
// Exporting the task so we can call it directly in our watch task, with the 'devMode' option
module.exports = browserifyTask;
You can solve it by specify extensions in ng-annotate options.
bundler.transform(ngAnnotate, { ext: ['.ts', '.js'] });
I realized I had this problem too, when I added uglifyify to the bundle transforms to produce minified builds.
An important aspect of my solution is that the missing, explicit $inject statements, that ng-annotate should have inserted, doesn't matter until the code is actually minified. Luckily, UglifyJS2, which does the actual minification in uglifyify, got support for handling ng-annotate's ngInject comments in version 2.4.9 (in January, 2014).
So, the solution that worked for me was to install uglifyify:
npm install --save-dev uglifyify
and add the following uglifyify transform to the Browserify bundle:
b.transform({
global: true,
mangle: false,
comments: true,
compress: {
angular: true
}
}, 'uglifyify');
This will make UglifyJS2 insert the appropriate $inject statements into your code before it is minified.
So, to summarize, I did not have a solution for only using ng-annotate, but my solution will add the necessary $inject statements before the code is minified, which is what matters in most cases.

What is the correct way to load polyfills and shims with Browserify

I'm building a web app and I'm getting to know and love Browserify. One thing has bugged me though.
I'm using some ES6 features that need to be shimmed/polyfilled in older browsers such as es6-promise and object-assign (packages on npm).
Currently I'm just loading them into each module that needs them:
var assign = require('object-assign');
var Promise = require('es6-promise');
I know this is definitely not the way to go. It is hard to maintain and I would like to use the ES6 features transparently instead of having to "depend" on them via requires.
What's the definitive way to load shims like these? I've seen several examples around the internet but they're all different. I could:
load them externally:
var bundle = browserify();
bundle.require('s6-promise');
// or should I use it bundle.add to make sure the code is runned???
The problem I have here is that I don't know which order the modules
will be loaded in in the browser. So the polyfilling might not have happened
yet at call sites that need the polyfilled functionality.
This has the additional downside that backend code cannot benefit from these
polyfills (unless I'm missing something).
use browserify-shim or something similar. I don't really see how this would work for ES6 features.
manually set up the polyfilling:
Object.assign = require('object-assign');
Don't require polyfills in your modules, that's an anti-pattern. Your modules should assume that the runtime is patched (when needed), and that should be part of the contract. A good example of this is ReactJS, where they explicitly define the minimum requirement for the runtime so that the library can work: http://facebook.github.io/react/docs/working-with-the-browser.html#browser-support-and-polyfills
You could use a polyfill service (e.g.: https://cdn.polyfill.io/) to include an optimized script tag at the top of your page to guarantee that the runtime is patched correctly with the pieces you need, while modern browsers will not get penalized.
This is the method that I'm using. The key is that you have to export your polyfill properly at the top of your main entry file.
The following won't work:
// Using ES6 imports
import './polyfill';
// Using CommonJS style
require('./polyfill');
... // rest of your code goes here
You actually need to export the polyfill:
// Using ES6 export
export * from './polyfill';
// Using CommonJS style
var polyfill = require('./polyfill');
... // rest of your code goes here
Your polyfills will load correctly if you do either of the latter methods.
Below you can find examples of my polyfills.
polyfill.js:
import './polyfill/Array.from';
import './polyfill/Object.assign';
Object.assign:
if (typeof Object.assign !== 'function') {
(function iife() {
const ObjectHasOwnProperty = Object.prototype.hasOwnProperty;
/**
* Copy the values of all enumerable own properties from one source
* object to a target object. It will return the target object.
* #param {Object} target The target object.
* #param {Object} source The source object.
* #return {Object} The target object.
*/
function shallowAssign(target, source) {
if (target === source) return target;
Object.keys(source).forEach((key) => {
// Avoid bugs when hasOwnProperty is shadowed
if (ObjectHasOwnProperty.call(source, key)) {
target[key] = source[key];
}
});
return target;
}
/**
* Copy the values of all enumerable own properties from one source
* object to a target object. It will return the target object.
* #param {Object} target The target object.
* #param {Object} source The source object.
* #return {Object} The target object.
*/
Object.assign = function assign(target, ...sources) {
if (target === null || target === undefined) {
throw new TypeError('Cannot convert undefined or null to object');
}
sources.forEach((source) => {
if (source !== null) { // Skip over if undefined or null
shallowAssign(Object(target), Object(source));
}
});
return target;
};
}());
}
One solution that worked for me was to use bundle.add
I split my bundle in 2 parts, app.js for app code, and appLib.js for libraries (this one will be cached as it does not change oftenly).
See https://github.com/sogko/gulp-recipes/tree/master/browserify-separating-app-and-vendor-bundles
For appLibs.js I use bundle.add for polyfills, as they must be loaded when the script is loaded, while I use bundle.require for other libs, that will be loaded only when required inside app.js.
polyfills.forEach(function(polyfill) {
b.add(polyfill);
});
libs.forEach(function(lib) {
b.require(lib);
});
The page loads these 2 bundles in order:
<head>
...
<script type="text/javascript" src="appLibs.js" crossorigin></script>
<script type="text/javascript" src="app.js" crossorigin></script>
...
</head>
This way it seems safe to assume that all polyfills will be loaded even before other libs are initialized. Not sure it's the best option but it worked for me.
My complete setup:
"use strict";
var browserify = require('browserify');
var gulp = require('gulp');
var gutil = require('gulp-util');
var handleErrors = require('../util/handleErrors');
var source = require('vinyl-source-stream');
var watchify = require("watchify");
var livereload = require('gulp-livereload');
var gulpif = require("gulp-if");
var buffer = require('vinyl-buffer');
var uglify = require('gulp-uglify');
// polyfills should be automatically loaded, even if they are never required
var polyfills = [
"intl"
];
var libs = [
"ajax-interceptor",
"autolinker",
"bounded-cache",
"fuse.js",
"highlight.js",
"imagesloaded",
"iscroll",
"jquery",
"keymaster",
"lodash",
"medium-editor",
"mime-db",
"mime-types",
"moment",
"packery",
"q",
"rangy",
"spin.js",
"steady",
"store",
"string",
"uuid",
"react-dnd"
];
// permits to create a special bundle for vendor libs
// See https://github.com/sogko/gulp-recipes/tree/master/browserify-separating-app-and-vendor-bundles
gulp.task('browserify-libs', function () {
var b = browserify({
debug: true
});
polyfills.forEach(function(polyfill) {
b.add(polyfill);
});
libs.forEach(function(lib) {
b.require(lib);
});
return b.bundle()
.on('error', handleErrors)
.pipe(source('appLibs.js'))
// TODO use node_env instead of "global.buildNoWatch"
.pipe(gulpif(global.buildNoWatch, buffer()))
.pipe(gulpif(global.buildNoWatch, uglify()))
.pipe(gulp.dest('./build'));
});
// Inspired by http://truongtx.me/2014/08/06/using-watchify-with-gulp-for-fast-browserify-build/
gulp.task('browserify',['cleanAppJs','browserify-libs'],function browserifyShare(){
var b = browserify({
cache: {},
packageCache: {},
fullPaths: true,
extensions: ['.jsx'],
paths: ['./node_modules','./src/'],
debug: true
});
b.transform('reactify');
libs.forEach(function(lib) {
b.external(lib);
});
// TODO use node_env instead of "global.buildNoWatch"
if ( !global.buildNoWatch ) {
b = watchify(b);
b.on('update', function() {
gutil.log("Watchify detected change -> Rebuilding bundle");
return bundleShare(b);
});
}
b.on('error', handleErrors);
//b.add('app.js'); // It seems to produce weird behaviors when both using "add" and "require"
// expose does not seem to work well... see https://github.com/substack/node-browserify/issues/850
b.require('app.js',{expose: 'app'});
return bundleShare(b);
});
function bundleShare(b) {
return b.bundle()
.on('error', handleErrors)
.pipe(source('app.js'))
.pipe(gulp.dest('./build'))
// TODO use node_env instead of "global.buildNoWatch"
.pipe(gulpif(!global.buildNoWatch, livereload()));
}
As you can see
Or use the polyfill service at
https://cdn.polyfill.io/v2/docs/

Resources