How to use gulp-traceur and gulp-webpack? - javascript

I'm trying to compile ES6 js files. I use gulp-traceur and gulp-wepback in gulp pipe line.
gulp.task('default', function () {
return gulp.src('js/app.js')
.pipe(traceur())
.pipe(webpack())
.pipe(concat('app.js'))
.pipe(rename({suffix: '.min'}))
.pipe(uglify())
.pipe(gulp.dest('build/js'));
When running gulp. I take error: Unexpected reserved word. You may need an appropriate loader to handle this file type. On the line which contains a "class" word. (ES6 Syntax)
I can't figure out how to use these plugins together?

This setup would pass 'js/app.js' to traceur, but none of the related files, and webpack will then start from that transpiled file and process the rest as normal JS. I'm actually not even sure webpack will get the transpile version of app.js.
The proper way is to use webpack for the main entry point, and tell webpack to transpile all files it comes across. I'd also recommend using Webpack's uglifyjs logic instead of tacking it on after-the-fact with gulp.
gulp.task('default', function () {
return gulp.src('js/app.js')
.pipe(webpack({
module: {
loaders: [{
test: /^(?!.*(bower_components|node_modules))+.+\.js$/,
loader: 'traceur'
}]
},
plugins: [
new webpack.optimize.UglifyJsPlugin()
]
})
.pipe(concat('app.js'))
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest('build/js'));
});

Related

Gulp concat, uglify handling ES6 exported libraries

I use Gulp to merge a few javascripts as well as uglify them. When I tried to do it with countUp (can be other script as well) I've got an error.
Uncaught SyntaxError: Unexpected token 'export'
It tries to export the javascript back to the script tag. Now my javascript file is not just one script, but many.
How can I make it work? Is there a tool to convert it to common js or maybe a better way to include it with gulp?
Script
A part of my gulp-file looks like below:
function script() {
return gulp
.src(js.src)
.pipe(concat(js.filename))
.pipe(gulp.dest(js.dest))
.pipe(uglify())
.pipe(rename({ extname: ".min.js" }))
.pipe(gulp.dest(js.dest));
}
You can use a gulp task to convert es6 modules to other types:
const babel = require('gulp-babel'),
gulp.task('es6-commonjs',['clean-temp'], function(){
return gulp.src(['app/*.js','app/**/*.js'])
.pipe(babel({ modules: 'common' }))
.pipe(gulp.dest('dest/temp'));
});
Then use this task in your gulp pipe. More info here.

Transpile a bunch of ES7 js files into compatible files

I have a folder with a bunch of javascript. I want to be able to use recent js syntax (especially await/async). But the target should compatible with most browsers.
Since these javascript files will be used standalone (will be imported in a 3rd party app as plugin), I want to respect these scheme:
src/file1.js ==> dist/file1.js
src/sub/file2.js ==> dist/sub/file2.js
...
each files should be transpiled into a es5 js file.
I'm using gulp 4 as build tool.
How to reach my goal ?
First try : use babel-gulp:
import gulp from 'gulp';
import sourcemaps from 'gulp-sourcemaps';
import babel from 'gulp-babel';
const javascript = () => {
return gulp.src('src/**/*.js')
.pipe(sourcemaps.init())
.pipe(babel({
"presets": [
["#babel/preset-env", {
"targets": {
"browsers": [">0.25%", "not ie 11", "not op_mini all"]
}
}]
]
}))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('dist'));
};
The build succeeds, but at runtime, it fails with ReferenceError: regeneratorRuntime is not defined
Second try, using browserify and #babel/polyfill, inspired from Browserify + Globs (multiple destination)
Added require("#babel/polyfill"); at top of my javascript files.
in gulp file:
const javascript2 = () => {
return gulp.src('src/**/*.js', {
read: false
}) // no need of reading file because browserify does.
.pipe(tap(function(file) {
file.contents = browserify(file.path).bundle();
}))
.pipe(buffer())
.pipe(sourcemaps.init({
loadMaps: true
}))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('dist'));
};
The build succeed, but the file is not transpiled (async keywords remain) and moreover, the whole babel polyfills are included in the output (and it's quite big) which conflicts with the target app (the app is also redefining startsWith function).
It looks like you are trying to set up a development environment. I would suggest using webpack instead of gulp, 'cause it's more relevant these days. Here's the guide I used to set one up: https://www.valentinog.com/blog/webpack-tutorial/.

Unable to use the transform-object-rest-spread while piping to babelify from browserify

I'm trying to use the transform-object-rest-spread babel plugin in my gulp build pipeline.
Normally I would add this as a plugin in the .babelrc file, but this pipeline is a new addition that runs parallel to an older gulp pipeline that needs different babel options, so the plugins need to be specified in the pipeline.
This is the gulp task I have built out currently:
gulp.task('frontend-browserified-js', () => {
var stream = browserify(`${files.frontendbrowserifiedjs.sourcePath}/${files.frontendbrowserifiedjs.entryPointName}`)
.transform(vueify)
.transform(babelify.configure({
presets: ['es2015'],
plugins: ["transform-runtime", "transform-object-rest-spread"]
}))
// .transform('babelify', {
// })
.bundle()
.on('error', handleError)
.pipe(fs.createWriteStream(`${files.frontendbrowserifiedjs.dest}/${files.frontendbrowserifiedjs.bundleName}`))
function handleError(error) {
console.error(error.stack)
console.log(chalk.red('hit error while gulping.'))
}
})
From the pipeline above:
presets: ['es2015'], // this preset _does_ work
plugins: ["transform-runtime", "transform-object-rest-spread"] // but these plugins are not recognized as far as I can tell
I keep hitting the following error while gulping:
Is there a correct way to pass in the plugins for a specific pipeline like this?

Migrating legacy library to ES2015-style modules

I have a javascript library intented to work in the browser, that I package with the following kind of gulpfile:
gulp.task("build", function() {
return gulp.src(sourceFiles)
.pipe(sourcemaps.init())
.pipe(concat("lib.js"))
.pipe(sourcemaps.write())
.pipe(gulp.dest("dist/"));
});
I want to start migrating this library to ES2015, using Babel.
For now, each source file in the src/ folder represents a module and is written using the following convention.
In src/MyModule.js:
MyLib.MyModule = (function () {
var module = {};
// code here...
return module;
})();
I want to migrate these scripts to ES2015-style modules, but I still want my releases to contain a single script (here lib.js). The consumers of my library would then load my modules using AMD implementations (e.g. require.js).
Is it possible to achieve such a thing? How would I do this?
EDIT:
I don't need my modules to remain nested like they currently are (Foo.Bar.Baz). But I do need my modules to be compatible with Flow.
As suggested by #JoeClay, I ended up packing my code using Webpack. I am setting it up to output in the UMD format, for better portability. Here is a summary of my gulpfile.js:
var gulp = require('gulp');
var sourcemaps = require('gulp-sourcemaps');
var webpack = require('webpack');
var webpackStream = require('webpack-stream');
var babel_loader = {
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: babel_presets,
plugins: babel_plugins
}
};
var webpackConfig = {
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-app.js',
library: 'MyApp',
libraryTarget: 'umd'
},
module: {
loaders: [
babel_loader
]
},
externals: externals,
devtool: "source-map"
};
gulp.task('build', function () {
return gulp.src("src/index.js")
.pipe(webpackStream(webpackConfig, webpack))
.pipe(sourcemaps.init({loadMaps: true}))
// some additional transformations here (e.g. uglify)...
.pipe(sourcemaps.write())
.pipe(gulp.dest('./dist/'));
});
Notes on source files
You don't need to list all of your source files. Webpack resolves the dependencies by itself by scanning recursively the sources, starting from the specified entry points (here just “src/index.js”). This approach required me to adapt my legacy code to using ES2015-style module import/export.
Notes on source maps
Webpack can generate source maps in a variety of flavours (here I use source-map, which is the best quality but takes more time to generate). If you want to do additional transformations to your code, you just have to use the gulp-sourcemaps plugin the usual way, so that the original source maps are adapted automatically. You need to initialize gulp-sourcemaps after the Webpack pass, using the loadMaps option.

How to use both 'gulp-babel' and 'gulp-browserify'

I try to write these code
gulp.task('script', function() {
'use strict'
return gulp.src(['app.js', 'components/**/*.jsx'])
.pipe(babel())
.pipe(browserify())
.pipe(gulp.dest("dist"));
});
but it shows some error:
SyntaxError:
/Users/Zizy/Programming/learn-react-js/components/CommentBox.jsx:58
<div className="commentBox">
^
ParseError: Unexpected token
at wrapWithPluginError (/Users/Zizy/Programming/learn-react-js/node_modules/gulp-browserify/index.js:44:10)
It seems that before .pipe(browserify()) the gulp did't transform the jsx code. But if I just remove .pipe(browserify()) I find that did transform, just cannot let babel and browserify work together.
I know maybe I can use like babelify or browserify plugin for babel though, I just want figure out the reason.
gulp-browserify doesn't quite work like that. You don't give it a bunch of buffers to collect and bundle.
You give it one file—the entry file—which it passes into Browserify. Browserify checks to see what other files the entry file references, then loads those files directly from the file system, meaning that you can't modify them with gulp plugins beforehand.
So, really, if we pretend you don't want to use Babel on your source files, your gulpfile should look like this, only passing in the entry file:
gulp.task('script', function() {
'use strict'
return gulp.src('app.js')
.pipe(browserify())
.pipe(gulp.dest("dist"));
});
However, note that gulp-browserify is no longer maintained, and this is exactly why. gulp plugins aren't supposed to read directly from the file system. That's why you're supposed to use Browserify (or, in your case, Babelify) directly with vinyl-source-stream as recommended in the gulp recipes. It's more idiomatic and less confusing.
That wraps up my answer to your question, but I'd like to add: if you're using the ES2015 module syntax (and you probably should be), there's a better way to do this. Browserify wraps all your modules separately in a bunch of code to make the programmatic CommonJS API work properly, but ES2015 modules have a declarative syntax, which makes it much easier for tools to operate on them statically. There's a tool called Rollup that takes advantage of this, allowing it to produce bundles that are smaller, faster, and more minfication-friendly than Browserify's.
Here's how you might use it with gulp:
var gulp = require('gulp'),
rollup = require('rollup-stream'),
babel = require('gulp-babel'),
source = require('vinyl-source-stream'),
buffer = require('vinyl-buffer');
gulp.task('script', function() {
return rollup({entry: 'app.js'})
.pipe(source('app.js'))
.pipe(buffer())
.pipe(babel())
.pipe(gulp.dest('dist'));
});
Starting from Babel 6 you need to declare the presets manually, check this.
Basically, in the root of your project you need a .babelrc with the following content:
{
"presets": [ "es2015", "react" ]
}
And the corresponding npm modules in package.json:
// package.json
{
"devDependencies": {
...
"babel-preset-es2015": "^6.1.18",
"babel-preset-react": "^6.1.18",
...
}
}
Here is a sample repository with gulp, babel and browserify
Following is the code snippet
gulp.task("js", (done) => {
const bundler = browserify({ entries: paths.js.source }, { debug: true }).transform(babel);
bundler.bundle()
.on("error", function (err) { console.error(err); this.emit("end"); })
.pipe(source(paths.build.destMinJSFileName))
.pipe(buffer())
.pipe(sourcemaps.init({ loadMaps: true }))
.pipe(uglify())
.pipe(sourcemaps.write(paths.js.destMapFolder))
.pipe(gulp.dest(paths.build.destBuildFolder));
done();
});

Categories

Resources