DEV Community

Sarah Hassan
Sarah Hassan

Posted on

Compile and Bundle Javascript es6 with Browserify + Babelify + Gulp

My story began while I was trying to use the tiny slider npm package in my project and I used Gulp as my task runner.

I got an error when I tried to import the tiny slider js file in the script file of my project.

// my gulp file
const { src, dest } = require('gulp');
// minify JS
const uglify = require('gulp-uglify');
// support JS for old browsers
const babel = require('gulp-babel');
// create source map files to JS
const sourcemaps = require('gulp-sourcemaps');
// rename files
const rename = require('gulp-rename');
const replace = require('gulp-replace');

const srcFiles = {
  jsPath: 'src/js/**/*.js'
};

const distFiles = {
  distJSPath: 'dist/js',
};

// my js task
function jsTask() {
  return (
    src([srcFiles.jsPath])
      // To load existing source maps
      // This will cause sourceMaps to use the previous sourcemap to create an ultimate sourcemap
      .pipe(gulpif(!production, sourcemaps.init({ loadMaps: true })))
      .pipe(
        gulpif(
          production,
          babel({
            presets: ['@babel/preset-env'],
          })
        )
      )
      .pipe(concat('all.js'))
      .pipe(gulpif(production, rename({ extname: '.min.js' })))
      .pipe(gulpif(production, uglify()))
      .pipe(gulpif(!production, sourcemaps.write('./')))
      .pipe(dest(distFiles.distJSPath))
  );
}
Enter fullscreen mode Exit fullscreen mode
// my script file
import { tns } from '../../node_modules/tiny-slider/src/tiny-slider';

Enter fullscreen mode Exit fullscreen mode

I got these errors:

Uncaught SyntaxError: Cannot use import statement outside a module

GET http://localhost:3000/node_modules/tiny-slider/src/tiny-slider net::ERR_ABORTED 404 (Not Found)

Let's start to explain what is the problem then we learn to solve it.

I used gulp-babel to compile ES6 to ES5. The problem is that require is not defined in the browser and in the ES5 syntax. So we need to search for another method to bundle all required js modules into one file.

We need this Browserify + Babelify combination to Compile & Bundle.

  • Browserify bundles js modules into one file to be used in the browser.

  • 'gulp-babel' didn't match with Browserify so, we will use Babelify instead to convert ES6 to ES5.

Steps are as the following:

npm i --save-dev browserify

npm i --save-dev  babelify

// has all packages needed for babelify to work
npm i --save-dev @babel/core

// to tap the specific preset to compile our script
npm i --save-dev @babel/preset-env


// grab source after bundling of browserify and check if entry source is still piped.
npm i --save-dev vinyl-source-stream

// to continue with using source map and uglify
npm i --save-dev vinyl-buffer

Enter fullscreen mode Exit fullscreen mode

In package.json, We need to specify the preset.

"devDependencies": {
    "@babel/core": "^7.13.8",
    "@babel/preset-env": "^7.9.6",
    "babel-core": "^6.26.3",
    "babel-preset-env": "^1.7.0",
    "babelify": "^8.0.0",
    "browser-sync": "^2.26.7",
    "browserify": "^17.0.0",
    .......
  },
  "babel": {
    "presets": [
      "@babel/preset-env"
    ]
  }
Enter fullscreen mode Exit fullscreen mode

In gulp file:

We can run js task for each group of files separately ex: a script for front-end and script for back-end.

// define entry for browserify
const jsSrc = 'module.js';
const jsFolder = 'src/js/';

// we can add a script for front-end and script for back-end and so on
const jsFiles = [jsSrc];
Enter fullscreen mode Exit fullscreen mode
const srcFiles = {
  jsPath: 'src/js/**/*.js',
  jsFiles: 'src/js/',
}
Enter fullscreen mode Exit fullscreen mode
const browserify = require('browserify');
const babelify = require('babelify');
const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer');

async function jsTask() {
  jsFiles.map(function (entry) {
    return (
      browserify({
        entries: [jsFolder + entry],
      })
        .transform(babelify, { presets: ['@babel/preset-env'] })
        .bundle()
        .pipe(source('all.js'))
        // To load existing source maps
        // This will cause sourceMaps to use the previous sourcemap to create an ultimate sourcemap
        .pipe(gulpif(production, rename({ extname: '.min.js' })))
        .pipe(buffer())
        .pipe(gulpif(!production, sourcemaps.init({ loadMaps: true })))
        // .pipe(concat('all.js'))
        .pipe(gulpif(production, uglify()))
        .pipe(gulpif(!production, sourcemaps.write('./')))
        .pipe(dest(distFiles.distJSPath))
    );
  });
}

Enter fullscreen mode Exit fullscreen mode

Resources that help me to solve the problem:

Hope this article helps, feel free to share it with your friends, any feedback will be appreciated :)

Thanks for reading!

Top comments (0)