babelify pipe results in: The code generator has deoptimised the styling of "/.../jquery.js" as it exceeds the max of "100KB" - node.js

I'm trying to create a single js file containing jquery, bootstrap and reactjs components using a gulp task:
app.jsx:
var React = require('react');
var ReactDOM = require('react-dom');
var HelloWorld = require('./Application.jsx');
var $, jQuery = require('../../libraries/jquery/dist/jquery');
var bootstrap = require('../../libraries/bootstrap-sass/assets/javascripts/bootstrap');
ReactDOM.render(
<Application />,
document.getElementById('example')
);
gulp task:
gulp.task('js', function () {
browserify('./public/javascripts/src/app.jsx')
.transform(babelify, {presets: ["es2015", "react"]})
.bundle()
.pipe(source('app.js'))
.pipe(gulp.dest('public/javascripts/build/'));
});
When running gulp, I get the following message:
[BABEL] Note: The code generator has deoptimised the styling of "/Users/.../jquery/dist/jquery.js" as it exceeds the max of "100KB".
How I design the gulp task, so that jquery and bootstrap does not pass the babelify pipe?

One possible solution is to add an ignore key to your babelify configuration so that it looks like something along the lines of:
.transform(babelify, {ignore: ['./libraries/**/*'], presets:["es2015", "react"]})
This should keep bableify from messing with your lib files that are already es5/minified/production ready.
(You may need to adjust the path a little bit... not 100% of your project structure)

Related

Generate SourceMaps for a single js file which includes modules with npm require and gulp

I'll begin straight off with an example of my code structure. Assume the following three trivial files reside inside the same directory called /path/from/root/js/src
module1.js:
console.log(1);
module2.js:
console.log(2);
app.js:
require('./module1');
require('./module2');
Then, I am using the following gulp task to compile javascript into one file with gulp:
var gulp = require('gulp');
var sourcemaps = require('gulp-sourcemaps');
var path = require('path');
var browserify = require('gulp-browserify');
gulp.task('default', function() {
gulp.src(['./js/src/app.js'])
.pipe(sourcemaps.init())
.pipe(browserify()).on('error', function(err){
console.log(err);
})
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(function( file ) {
file.base = path.dirname(file.path);
return path.join(path.dirname(file.path), '/../');
}))
});
After running gulp I am getting the compiled javascript app.js which just logs 1 2 and an app.js.map as expected, but there is no reference to the original file in the browser.
You can check that by looking at the console lines 1 and 2, they are referenced by app.js, not by module1|2.js. If I needed to fix a bug I'd have no idea which file is generating the console notations in the future as the files grow bigger in my project.
What am I doing wrong? Am I not using the sourcemaps correctly?
The app.js.map file doesn't reference the modules, it looks like this:
{
"version":3,
"names":[],
"mappings":"",
"sources":["app.js"],
"sourcesContent":["require('./module1');\r\nrequire('./module2');"],
"file":"app.js"
}
Using rollup
After trying various stuff and build packages online, I have found a solution to my problem with the use of rollup instead of browserify. In case someone is interested, I will add here my trivial build in basic usage with rollup :
module1.js and module2.js remain as are.
app.js becomes
import {m1} from './module1';
import {m2} from './module2';
And my gulpfile becomes
var gulp = require('gulp'),
rollup = require('rollup')
;
gulp.task('default', function () {
return rollup.rollup({
entry: "./js/src/app.js",
})
.then(function (bundle) {
bundle.write({
format: "umd",
moduleName: "library",
dest: "./js/app.js",
sourceMap: true
});
})
});
Now open your html file which includes /js/app.js and you'll see in your console 1 referenced by module1.js and 2 referenced by module2.js
Looks like rollup doesn't support require by default, but the import {...} from ... syntax is more minimalistic and part of ES6, so it might be better for me to start using it instead.
Source from official documentation: https://rollupjs.org/#using-rollup-with-gulp
Further reading for a more complex build (I haven't walked through these steps yet, but looks promising): https://github.com/rollup/rollup-starter-project
All hail mighty messy malicious Javascript for the troubles it leads upon us !
I have found a more relative solution to the problem, so I'm creating a new answer for it. I have noticed that the gulp-browserify package I was using was deprecated, so I checked for an updated usage.
My package.json dependencies are:
"devDependencies": {
"babel-preset-es2015": "^6.24.1",
"babelify": "^7.3.0",
"browserify": "^14.4.0",
"gulp": "^3.9.1",
"gulp-sourcemaps": "^2.6.0",
"gulp-uglify": "^3.0.0",
"gulp-util": "^3.0.8",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0"
}
My gulpfile.js for a basic build looks like this:
'use strict';
var browserify = require('browserify');
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
var gutil = require('gulp-util');
gulp.task('default', function () {
// set up the browserify instance on a task basis
var b = browserify({
entries: './js/src/app.js',
debug: true
}).transform("babelify", {presets: ["es2015"]});
return b.bundle()
.pipe(source('app.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
// Add transformation tasks to the pipeline here.
//.pipe(uglify())
.on('error', gutil.log)
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('./js/'));
});
For a production build, you can uncomment the uglify command.
Babelify is there to allow ES5 syntax (didn't test, but probably you can instead use the *2017 package too).
Sources:
1. Gulp setup for Browserify
2. Babel setup for Browserify

RequireJS + Babel + JSX

I'm trying to invoke in-browser JSX transformations using Babel.
I'm loading an AMD JS module in the browser using the following:
require(["nbextensions/ht"] function(ext){});
Which eventually imports this "ui" module, which has calls a function to render JSX.
However, this doesn't seem to be triggering Babel's in-browser JSX transformer.
Is it even possible to call Babel's JSX Transformer from within a RequireJS context?
var BOWER = '/nbextensions/ht/bower_components'
var COMPONENTS = '/nbextensions/ht/components'
var NODE_MODULES = '/nbextensions/ht/node_modules'
requirejs.config({
paths: {
es6: NODE_MODULES + "/requirejs-babel/es6",
babel: NODE_MODULES + "/requirejs-babel/babel-5.8.22.min"
}
})
define([
BOWER + '/react/react.min.js',
"es6!" + COMPONENTS + "/App.jsx"
],function(React, App){
console.log("Loaded React v" + React.version)
var ui = {}
ui.render = function() {
React.render(<App/>, document.getElementById("ht_main"))
}
return ui
})
Ah, figured it out. The method used here https://github.com/podio/requirejs-react-jsx does work, but the RequireJS JSX transformation only works on the imported module (main.js cannot have JSX mixed in).
Therefore, the Component module should simply be wrapped in a function prototype that exposes a render() method to React.render.
Refer to the example on the github page.

Babel won't ignore my module regex

I'm using Mocha to run tests on my React components, so I need Babel in my Mocha bootstrap to transpile the jsx requires. In my bootstrap.js I start with
global.babel = require("babel/register")({
ignore: [/node_modules/, '**/scss*', /sinon/, /foo/]
});
According to the docs, ignore accepts "A glob, regex, or mixed array of both" But its weird because the /node_modules/, /sinon/ regexes work, but the **/scss* and /foo/ don't.
For example, here's the top of the component that fails the require:
var React = require('react');
var Router = require('react-router');
var Link = Router.Link;
var foo = require('foo');
var StyleSheet = require('../../scss/core/Linker');
Fails with:
1) app/core/Linker.jsx "before each" hook:
Error: Cannot find module 'foo'
at Object.<anonymous> (app/core/Linker.jsx:4:11)
at Context.<anonymous> (test/app/helpers/linker-test.js:10:23)
I start the tests like so:
mocha test --recursive --reporter spec --timeout 30000
Am I doing it wrong, or losing the babel ignore by the time the required component test is loaded up?

Browserify + Remapify (Gulp workflow)

I've successfully got Browserify to compile my JavaScript entry files, but I want to utilise the Remapify plugin so as to not have to specify the full relative path upon requiring a module every time.
For example:
require('components/tabs.js')
Rather than:
require('../../components/tabs/tabs.js').
But I cannot get the shorter module references to map to the corresponding file... "Error: Cannot find module [specified_ref] from [file]".
Have I misconfigured Remapify, or is there something wrong with my wider Browserify setup? I am new to Broswerify and Gulp having previously used Require.js and Grunt. Any help would be greatly appreciated. Please let me know if you need any more information about my setup.
If alternatively you can recommend an alternative Gulp task file that will do all of this, thereby throwing my current task out the window, by all means. I wasn't able to find many Browserify + Remapify examples.
Directory Structure
I have my modules (components) in the following directory: './src/components', so for example: './src/components/tabs/tabs.js'.
I am requiring these modules in a JS file for a given page of the app, which are in: './src/pages', so for example, './src/pages/portfolio/portfolio.js'.
Gulp Browserify Task
var gulp = require('gulp');
var config = require('../config');
var browserify = require('browserify');
var remapify = require('remapify');
var source = require('vinyl-source-stream');
var glob = require('glob');
var browserSync = require('browser-sync');
gulp.task('browserify', function(){
var entries = glob.sync(config.src.pages + '/**/*.js');
return browserify({
entries: entries,
debug: true
})
// (Remapify:)
.plugin(remapify, [{ src: config.src.components + '/**/*.js', expose: 'components', cwd: config.srcDir }])
.bundle()
.pipe(source('app.js'))
.pipe(gulp.dest(config.build.js))
.pipe(browserSync.reload({ stream: true }));
});
Page.js
'use strict';
var tabs = require('components/tabs.js'); // (Doesn't work, but I want it to)
// var tabs = require('../../components/tabs/tabs.js'); // (Does work)
Remapify has all sorts of problems. I suggest giving my pathmodify plugin a shot.
For your situation usage would look something like:
var pathmod = require('pathmodify');
// ...
.plugin(pathmod(), {mods: [
pathmod.mod.dir('components', '/path/to/src/components'),
]})

How to ignore libraries in browserify programmatic api

Assume the below code is found in bundler.js and tracing entry.js leads to var B = require('backbone'); (Backbone is a dependency installed as declared in package.json).
var browserify = require('browserify');
var bundle = new browserify();
bundle.add('entry.js');
bundle.bundle({
noParse: ['backbone']
});
Executing this bundler yields a stream that contains the original backbone source. Based on browserify's command line options I expected it to skip backbone alltogether. Reading through the source, I expected perhaps the following would work:
var browserify = require('browserify');
var bundle = new browserify({
noParse: ['backbone']
});
bundle.add('entry.js');
bundle.bundle();
Though backbone source still appears in the stream output.
Is it possible to use --noparse=FILE as a configuration option in this application of the api?
As you can see from here the --noparse option provided on the command line is passed to the browserify({ }) call.
So in order to tell browserify to not parse jquery and three.js you have to pass the full path to your jquery and three.js files.
Example:
browserify({
noParse: [
require.resolve('./vendor/jquery'),
require.resolve('./vendor/three')
]
})
.require(require.resolve('./entry.js'), { entry: true })
.bundle();
var browserify = require("browserify")
browserify({entries: ['./src/client/app.js']})
.ignore('jquery')
That would make browserify ignore jquery, and then jquery can be added on index.html directly.

Resources