1

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.

Antoine
  • 1,782
  • 1
  • 14
  • 32
  • 1
    This is exactly the problem that module bundlers like [Webpack](https://webpack.js.org) and [Browserify](http://browserify.org/) are designed to solve. You could either replace your Gulp build with one of them, or [integrate one of them into your config](http://stackoverflow.com/questions/40573196/using-webpack-2-from-gulp-webpack-stream-for-webpack-2). – Joe Clay Feb 06 '17 at 10:47
  • @JoeClay Thanks for the links. How would a consumer load and use my library with these solutions? – Antoine Feb 06 '17 at 10:50
  • 1
    Depends how you configure it. Can't speak for Browserify as I've never really used it, but Webpack can be set up to output CommonJS, AMD, global variables, etc. I'd recommend outputting as [UMD](https://github.com/umdjs/umd), which allows your library to be compatible with all of them. See this guide for more info: https://webpack.js.org/guides/author-libraries/ – Joe Clay Feb 06 '17 at 10:55

1 Answers1

0

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.

Antoine
  • 1,782
  • 1
  • 14
  • 32