K
K
Konstantin Basharkevich2016-07-27 11:04:02
JavaScript
Konstantin Basharkevich, 2016-07-27 11:04:02

How to write gulp-task to build modular js with browserify?

Hello.
Please tell me how to write a gulp task to build *.js files from typescript using browserify with the following conditions:

  • the project is a portal with sections that are different in content and functionality, and therefore I want to generate not a single bundle.js for the entire site, but separate scripts for each section
  • common modules would like to be moved to a separate common.js file

My own research led me to the factor-bundle plugin for browserify, however, as I understand it, when using it, you need to clearly specify the input and output files. But this is rather inconvenient, I want the script to be universal and work according to a template. Another point that is not clear to me is how to create a source map for each script file and put it in a specific directory.
I would like to see the following result:
/<project_dir>
    /public
        /static
            /js
                /maps
                    ...
                /modules
                    ...
                common.js
    /static
        /typescript
            /compile
                /modules
                    ...
            /import
                ...

Files from the static/typescript/compile folder should, after compiling into regular js and including all dependencies, fall into the public/static/js directory with their name and relative path preserved (i.e. files from the modules folder go to modules), generating common .js and source maps (in the public/static/js/maps directory).
In no case do I ask you to provide me with a ready-made solution, just tell me in which direction to dig. I understand that you can separately search for files by pattern, generate resp. arrays of input and output files and create any missing directories. But isn't there a more elegant solution? Plus, the issue with source maps remains unresolved...

Answer the question

In order to leave comments, you need to log in

1 answer(s)
K
Konstantin Basharkevich, 2016-07-29
@qodunpob

I asked myself - I will answer. As I understand it, neither browserify nor webpack can specify wildcard as entry points. In my search, I came up with two solutions.
If you solve the problem using browserify, you need to take care of generating a list of files and creating all the necessary directories yourself. You will get something like this:

gulp.task('compile-typescript', function () {
    let browserify = require('browserify'),
        factor = require('factor-bundle'),
        tsify = require('tsify'),
        path = require('path'),
        source = require('vinyl-source-stream'),
        glob = require('glob'),
        mkdirp = require('mkdirp'),

        srcDir = 'static/typescript/compile/',
        distDir = 'public/static/js/',

        entries = glob.sync(srcDir + '**/*[email protected](ts|tsx)'),
        outputs = [],

        mkdirProccess = [],

        typescriptOptions = {
            module: 'commonjs',
            target: 'es5',
            jsx: 'React'
        };

    entries.forEach(function (filename) {
        let relativePath = path.dirname(path.relative(srcDir, filename)),
            basename = path.basename(filename, path.extname(filename)) + '.js';

        if (relativePath === '.') {
            relativePath = '';
        } else {
            relativePath += '/';
            mkdirProccess.push(new Promise(function (resolve, reject) {
                mkdirp(distDir + relativePath, function (error) {
                    if (error) reject(error);
                    else resolve();
                });
            }));
        }

        outputs.push(distDir + relativePath + basename);
    });

    Promise.all(mkdirProccess)
        .then(function () {
            browserify({
                entries,
                debug: true
            })
                .plugin(tsify, typescriptOptions)
                .plugin(factor, {
                    outputs,
                    threshold: 2
                })
                .bundle()
                .pipe(source('common.js'))
                .pipe(gulp.dest(distDir));
        });
});

However, in this case, source maps will be included in the final files and contain incorrect links to the sources.
But using webpack-stream can greatly simplify the solution and get the desired result:
gulp.task('compile-typescript', function () {
    let webpack = require('webpack-stream'),
        named = require('vinyl-named'),

        srcDir = 'static/typescript/compile/',
        distDir = 'public/static/js/';

    return gulp.src(srcDir + '**/*[email protected](ts|tsx)')
        .pipe(named(file => file.relative.replace(/\.tsx?$/, '')))
        .pipe(webpack(require('./webpack.config.js')))
        .pipe(gulp.dest(distDir));
});

'use strict';

const webpack = require('webpack');

module.exports = {
    resolve: {
        extensions: ['', '.webpack.js', '.web.js', '.js', '.ts', '.tsx']
    },
    output: {
        sourceMapFilename: 'maps/[file].map'
    },
    module: {
        loaders: [
            { test: /\.tsx?$/, loader: 'ts-loader' }
        ]
    },
    plugins: [
        new webpack.NoErrorsPlugin(),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'common',
            minChunks: 3
        })
    ],
    devtool: 'source-map'
};

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es5",
    "jsx": "React",
    "sourceMap": true
  }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question