Search code examples
javascriptjquerywebpackgulp

Gulp webpack load jquery only once


I've got two Gulp tasks in my gulpfile.js. It's used for a website.

The first one compiles with webpack the main js file, used on all pages of the site (mainly visuals), and combines it to a single file.

gulp.task('scripts', function(callback) {
let firstBuildReady = false;

function done(err, stats) {
    firstBuildReady = true;
    if (err) { // hard error, see https://webpack.github.io/docs/node.js-api.html#error-handling
        return;  // emit('error', err) in webpack-stream
    }
    gulplog[stats.hasErrors() ? 'error' : 'info'](stats.toString({
        colors: true
    }));
}

let options = {
    output: {
        publicPath: '/js/',
        filename: isDevelopment ? '[name].js' : '[name]-[chunkhash:10].js'
    },
    watch:   isDevelopment,
    devtool: isDevelopment ? 'cheap-module-inline-source-map' : false,
    module:  {
        loaders: [{
            test: /\.js$/,
            //include: path.join(__dirname, "app/src/scripts/modules"),
            loader: 'babel-loader',
            query: {
               presets: ["env"]
            }
        }]
    },
    plugins: [
        new webpack.NoEmitOnErrorsPlugin(),
    ]
};

if (!isDevelopment) {
    options.plugins.push(new AssetsPlugin({
        filename: 'scripts.json',
        path:     __dirname + '/app/manifest',
        processOutput(assets) {
            for (let key in assets) {
                assets[key + '.js'] = assets[key].js.slice(options.output.publicPath.length);
                delete assets[key];
            }
            return JSON.stringify(assets);
        }
    }));
}

return gulp.src(jsSRC)
    .pipe(plumber({
        errorHandler: notify.onError(err => ({
            title:   'Scripts',
            message: err.message
        }))
    }))
    .pipe(named(function(file){
        return 'app'
    }))
    .pipe(webpackStream(options, null, done))
    .pipe(gulpIf(!isDevelopment, uglify()))
    .pipe(gulp.dest(jsDIST))
    .on('data', function() {
        if (firstBuildReady) {
            callback();
        }
    });

});

The second one compiles each js module as a single file - some js scripts, used on special pages. These scripts are included only there where needed.

gulp.task('webpack', function(callback) {
let firstBuildReady = false;

function done(err, stats) {
    firstBuildReady = true;
    if (err) {
        return;
    }
    gulplog[stats.hasErrors() ? 'error' : 'info'](stats.toString({
        colors: true
    }));
}

let options = {
    output: {
        publicPath: '/js/',
        filename: isDevelopment ? '[name].js' : '[name]-[chunkhash:10].js'
    },
    watch:   isDevelopment,
    devtool: isDevelopment ? 'cheap-module-inline-source-map' : false,
    module:  {
        loaders: [{
            test: /\.js$/,
            loader: 'babel-loader',
            query: {
               presets: ["env"]
            }
        }]
    },
    plugins: [
        new webpack.NoEmitOnErrorsPlugin()
    ]
};

if (!isDevelopment) {
    options.plugins.push(new AssetsPlugin({
        filename: 'webpack.json',
        path:     __dirname + '/app/manifest',
        processOutput(assets) {
            for (let key in assets) {
                assets[key + '.js'] = assets[key].js.slice(options.output.publicPath.length);
                delete assets[key];
            }
            return JSON.stringify(assets);
        }
    }));
}

return gulp.src('app/src/scripts/modules/*.js')
    .pipe(plumber({
        errorHandler: notify.onError(err => ({
            title:   'Webpack',
            message: err.message
        }))
    }))
    .pipe(named())
    .pipe(webpackStream(options, null, done))
    .pipe(gulpIf(!isDevelopment, uglify()))
    .pipe(gulp.dest(jsDIST))
    .on('data', function() {
        if (firstBuildReady) {
            callback();
        }
    });

});

But I have to include Jquery in every single file for the second task, otherwise it's not compiled. But Jquery is included in the main app.js file.

How can I solve it?

Thanks


Solution

  • Since it sounds like you're using a somewhat exotic way of loading JS in your application (instead of approaches like require.ensure), your easiest option may be to use Webpack externals when building your individual modules. Your main script/page will have to ensure that jQuery is globally exposed (like under window.$ or window.jQuery). Then, for your webpack config, include something like this:

    {
      // ...
      externals: {
        jquery: '$'
      }
    }
    

    This will substitute $ for all require('jquery') calls instead of including jquery in each JS bundle.