In webpack, CopyWebpackPlugin causes infinite loop when webpack is in watch mode. I tried to add watchOptions.ignored option but it doesn't seem to work.
My webpack config is following:
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const config = {
entry: {
'res': './src/index.js'
},
output: {
filename: '[name].min.js',
path: path.resolve(__dirname, 'dist')
},
mode: 'production',
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new CopyWebpackPlugin([
{ from: 'dist', to: path.resolve(__dirname, 'docs/js') }
], {})
],
watchOptions: {
ignored: path.resolve(__dirname, 'docs/js')
}
};
module.exports = config;
Any help would be appreciated.
With CopyWebpackPlugin, I've experienced the infinite loop too. I tried all kinds of CopyWebpackPlugin configurations with no luck yet. After hours of wasted time I found I could hook into the compiler and fire off my own copy method.
Running Watch
I'm using webpack watch to watch for changes. In the package.json, I use this config so I can run npm run webpackdev, and it will watch for file changes.
"webpackdev": "cross-env webpack --env.environment=development --env.basehref=/ --watch"
My Workaround
I've added an inline plugin with a compiler hook, which taps into AfterEmitPlugin. This allows me to copy after my sources have been generated after the compile. This method works great to copy my npm build output to my maven target webapp folder.
// Inline custom plugin - will copy to the target web app folder
// 1. Run npm install fs-extra
// 2. Add fix the path, so that it copies to the server's build webapp folder
{
apply: (compiler) => {
compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
// Debugging
console.log("########-------------->>>>> Finished Ext JS Compile <<<<<------------#######");
let source = __dirname + '/build/';
// TODO Set the path to your webapp build
let destination = __dirname + '/../dash-metrics-server/target/metrics-dash';
let options = {
overwrite: true
};
fs.copy(source, destination, options, err => {
if (err) return console.error(err) {
console.log('Copy build success!');
}
})
});
}
}
The Workaround Source
Here's my webpack.config.js in total for more context. (In this webpack configuration, I'm using Sencha's Ext JS ExtWebComponents as the basis.)
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { BaseHrefWebpackPlugin } = require('base-href-webpack-plugin');
const ExtWebpackPlugin = require('#sencha/ext-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const webpack = require('webpack');
const fs = require('fs-extra');
module.exports = function(env) {
function get(it, val) {if(env == undefined) {return val;} else if(env[it] == undefined) {return val;} else {return env[it];}}
var profile = get('profile', '');
var emit = get('emit', 'yes');
var environment = get('environment', 'development');
var treeshake = get('treeshake', 'no');
var browser = 'no'; // get('browser', 'no');
var watch = get('watch', 'yes');
var verbose = get('verbose', 'no');
var basehref = get('basehref', '/');
var build_v = get('build_v', '7.0.0.0');
const isProd = environment === 'production';
const outputFolder = 'build';
const plugins = [
new HtmlWebpackPlugin({template: 'index.html', hash: false, inject: 'body'}),
new BaseHrefWebpackPlugin({ baseHref: basehref }),
new ExtWebpackPlugin({
framework: 'web-components',
toolkit: 'modern',
theme: 'theme-material',
emit: emit,
script: './extract-code.js',
port: 8080,
packages: [
'renderercell',
'font-ext',
'ux',
'd3',
'pivot-d3',
'font-awesome',
'exporter',
'pivot',
'calendar',
'charts',
'treegrid',
'froala-editor'
],
profile: profile,
environment: environment,
treeshake: treeshake,
browser: browser,
watch: watch,
verbose: verbose,
inject: 'yes',
intellishake: 'no'
}),
new CopyWebpackPlugin([{
from: '../node_modules/#webcomponents/webcomponentsjs/webcomponents-bundle.js',
to: './webcomponents-bundle.js'
}]),
new CopyWebpackPlugin([{
from: '../node_modules/#webcomponents/webcomponentsjs/webcomponents-bundle.js.map',
to: './webcomponents-bundle.js.map'
}]),
// Debug purposes only, injected via script: npm run-script buildexample -- --env.build_v=<full version here in format maj.min.patch.build>
new webpack.DefinePlugin({
BUILD_VERSION: JSON.stringify(build_v)
}),
// This causes infinite loop, so I can't use this plugin.
// new CopyWebpackPlugin([{
// from: __dirname + '/build/',
// to: __dirname + '/../dash-metrics-server/target/test1'
// }]),
// Inline custom plugin - will copy to the target web app folder
// 1. Run npm install fs-extra
// 2. Add fix the path, so that it copies to the server's build webapp folder
{
apply: (compiler) => {
compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
// Debugging
console.log("########-------------->>>>> Finished Ext JS Compile <<<<<------------#######");
let source = __dirname + '/build/';
// TODO Set the path to your webapp build
let destination = __dirname + '/../dash-metrics-server/target/metrics-dash';
let options = {
overwrite: true
};
fs.copy(source, destination, options, err => {
if (err) return console.error(err)
console.log('Copy build success!');
})
});
}
}
];
return {
mode: environment,
devtool: (environment === 'development') ? 'inline-source-map' : false,
context: path.join(__dirname, './src'),
//entry: './index.js',
entry: {
// ewc: './ewc.js',
app: './index.js'
},
output: {
path: path.join(__dirname, outputFolder),
filename: '[name].js'
},
plugins: plugins,
module: {
rules: [
{ test: /\.(js)$/, exclude: /node_modules/,
use: [
'babel-loader',
// 'eslint-loader'
]
},
{ test: /\.(html)$/, use: { loader: 'html-loader' } },
{
test: /\.(css|scss)$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{ loader: 'sass-loader' }
]
}
]
},
performance: { hints: false },
stats: 'none',
optimization: { noEmitOnErrors: true },
node: false
};
};
So I know this question is very old at this point, but I was running into this endless loop issue again recently and found a couple of solutions.
Not the cleanest method, but if you add an "assets" folder, which can be completely empty, to the root of your project, it seems to only compile after your sources folder changes.
The better method I have found is within the webpack config. The original poster mentioned about using ignored which does seem to fix the issue if you instruct webpack to watch file changes after the initial build and to ignore your dist/output folder...
module.exports = {
//...
watch: true,
watchOptions: {
ignored: ['**/dist/**', '**/node_modules'],
},
};
Related
What I'm trying to achieve is to create a separate webpack assets file for copying static assets from the src folder to the web folder.
node version: 8.15.0
yarn version: 1.13.0
webpack: 4.19.1
copy-webpack-plugin: 6.0.0
To start, I already have a webpack.common.js file which deals with all the js files, and I have created the assets file, which can be seen below.
When I run
webpack --config=webpack/webpack.assets.js --mode development --progress --color
or
webpack --config=webpack/webpack.config.js --config=webpack/webpack.assets.js --mode development --progress --color --env development
I get this error ERROR in Path must be a string. Received undefined and I can't figure it out where it comes from.
By the way I just started dealing with webpack recently.
webpack.common.js
const webpack = require('webpack');
const path = require('path');
const PATHS = {
src: path.join(process.cwd(), 'src', 'js'),
dist: path.join(process.cwd(), 'web', 'js')
};
module.exports = {
entry: {
homepage: path.resolve(PATHS.src, 'pages/homepage.js'),
otherfile: path.resolve(PATHS.src, 'pages/othefile.js'),
}
output: {
path: PATHS.dist,
filename: '[name].js',
chunkFilename: '[name].js',
publicPath: '/js/'
},
...
}
webpack.assets.js
const webpack = require('webpack');
const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');
const PATHS = {
src: path.join(process.cwd(), 'src', 'svg'),
dist: path.join(process.cwd(), 'web', 'svg')
};
module.exports = (env) => {
const svgFormat = env === 'production' ? '[name].[hash].[ext]' : '[name].[ext]';
return merge(commmonConfig, {
entry: [
path.resolve(PATHS.src, 'logo1.svg'),
path.resolve(PATHS.src, 'logo2.svg')
],
output: {
path: PATHS.dist
},
module: {
rules: [
{
test: /\.(svg)$/,
use: [
{
loader: 'file-loader',
options: {
name: svgFormat,
},
},
],
},
]
},
plugins: [
new CopyPlugin([
{
from: PATHS.src,
to: PATHS.dist,
force: true,
toType: 'dir'
},
{
copyUnmodified: true,
debug: 'debug'
}
])
]
});
};
What I would like is to be able to run the assets commands with no errors, as the actual files get copied correctly.
Any ideas are very much appreciated!
You have passed your options object as a second pattern.
Move it outside of the patterns array and pass it as the second parameter instead:
plugins: [
new CopyPlugin(
[
{
from: PATHS.src,
to: PATHS.dist,
force: true,
toType: 'dir'
}
],
{
copyUnmodified: true,
debug: 'debug'
}
)
]
You get the error as your options object is being treated as a pattern but does not have a from property.
I'm using babel-plugin-react-css-modules and it seems to be creating the className/styleName, but for some reason it isn't outputting the CSS so that it can be read by the module.
Here's my application: launchpad
I'm using webpack 4.2.0/React 16 and use a babel configuration in the webpack.config imported from a separate config file as you can't set context in .babelrc.
here's the babel config:
{
loader: 'babel-loader',
options: {
'plugins': [
'react-hot-loader/babel',
'transform-runtime',
'transform-object-rest-spread',
'transform-class-properties',
['react-css-modules',
{
context: paths.javascript,
'generateScopedName': '[name]__[local]___[hash:base64:5]',
'filetypes': {
'.scss': {
'syntax': 'postcss-scss',
'plugins': ['postcss-nested']
}
},
'exclude': 'node_modules',
'webpackHotModuleReloading': true
}
]
],
'presets': [
'env',
'react',
'flow'
],
'env': {
'production': {
'presets': ['react-optimize']
}
}
}
}
And here is my webpack:
const webpack = require('webpack')
const path = require('path')
const paths = require('./webpack/config').paths
const outputFiles = require('./webpack/config').outputFiles
const rules = require('./webpack/config').rules
const plugins = require('./webpack/config').plugins
const resolve = require('./webpack/config').resolve
const IS_PRODUCTION = require('./webpack/config').IS_PRODUCTION
const IS_DEVELOPMENT = require('./webpack/config').IS_DEVELOPMENT
const devServer = require('./webpack/dev-server').devServer
const DashboardPlugin = require('webpack-dashboard/plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
// Default client app entry file
const entry = [
'bootstrap-loader/extractStyles',
path.join(paths.javascript, 'index.js')
]
plugins.push(
// Creates vendor chunk from modules coming from node_modules folder
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: outputFiles.vendor,
minChunks (module) {
const context = module.context
return context && context.indexOf('node_modules') >= 0
}
}),
// Builds index.html from template
new HtmlWebpackPlugin({
template: path.join(paths.source, 'index.html'),
path: paths.build,
filename: 'index.html',
minify: {
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true,
removeComments: true,
useShortDoctype: true
}
})
)
if (IS_DEVELOPMENT) {
// Development plugins
plugins.push(
// Enables HMR
new webpack.HotModuleReplacementPlugin(),
// Don't emmit build when there was an error while compiling
// No assets are emitted that include errors
new webpack.NoEmitOnErrorsPlugin(),
// Webpack dashboard plugin
new DashboardPlugin()
)
// In development we add 'react-hot-loader' for .js/.jsx files
// Check rules in config.js
rules[0].use.unshift('react-hot-loader/webpack')
entry.unshift('react-hot-loader/patch')
}
// Webpack config
module.exports = {
devtool: IS_PRODUCTION ? false : 'eval-source-map',
context: paths.javascript,
watch: IS_DEVELOPMENT,
entry,
output: {
path: paths.build,
publicPath: '/',
filename: outputFiles.client
},
module: {
rules
},
resolve,
plugins,
devServer
}
If you run npm start or yarn start the code will compile and run, and you can see a basic application layout. If you inspect the react code you will see that the style name is reflected in the component. What doesn't happen is that the style isn't being output. I can't seem to figure out why.
Any help is appreciated.
So I was able to reduce my bundle size from 13mb to 6.81mb
I did some optimizations like proper production configurations, optimizing libraries like lodash and replacing momentjs with date-fns.
Now got to a point where most packages do not exceed 1mb and most of them are dependencies installed by npm.
Using webpack-bundle-analyzer here is what my bundle looks like now
So do you guys think I can do something more to reduce the bundle size?
Maybe remove jquery and go vanilla js? But then it's only 1mb... Is there something I can do to significantly optimize the size?
Some more details if you'd like
This is how do my build NODE_ENV=production webpack
const webpack = require('webpack')
const path = require('path')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const OptimizeCSSAssets = require('optimize-css-assets-webpack-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin')
const config = {
entry: ['babel-polyfill', './src/index.js'],
output: {
path: path.resolve(__dirname, './public'),
filename: './output.js'
},
resolve: {
extensions: ['.js', '.jsx', '.json', '.scss', '.css', '.jpeg', '.jpg', '.gif', '.png'], // Automatically resolve certain extensions
alias: { // Create Aliases
images: path.resolve(__dirname, 'src/assets/images')
}
},
module: {
rules: [
{
test: /\.js$/, // files ending with js
exclude: /node-modules/,
loader: 'babel-loader'
},
{
test: /\.scss$/,
use: ['css-hot-loader', 'style-loader', 'css-loader', 'sass-loader', 'postcss-loader']
},
{
test: /\.jsx$/, // files ending with js
exclude: /node-modules/,
loader: 'babel-loader'
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loaders: [
'file-loader?context=src/assets/images/&name=images/[path][name].[ext]',
{
loader: 'image-webpack-loader',
query: {
mozjpeg: {
progressive: true
},
gifsicle: {
interlaced: false
},
optipng: {
optimizationLevel: 4
},
pngquant: {
quality: '75-90',
speed: 3
}
}
}
],
exclude: /node_modules/,
include: __dirname
}
]
},
plugins: [
new ExtractTextWebpackPlugin('styles.css'),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
// make sure this one with urls is always the last one
new webpack.DefinePlugin({
DDP_URL: getDDPUrl(),
REST_URL: getRESTUrl()
}),
new LodashModuleReplacementPlugin({collections: true})
],
devServer: {
contentBase: path.resolve(__dirname, './public'), // a directory or URL to serve HTML from
historyApiFallback: true, // fallback to /index.html for single page applications
inline: true, // inline mode, (set false to disable including client scripts (like live reload))
open: true // open default browser while launching
},
devtool: 'eval-source-map' // enable devtool for bettet debugging experience
}
module.exports = config
if (process.env.NODE_ENV === 'production') {
module.exports.plugins.push(
// https://reactjs.org/docs/optimizing-performance.html#webpack
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new webpack.optimize.UglifyJsPlugin(),
new OptimizeCSSAssets(),
new BundleAnalyzerPlugin()
)
}
function getDDPUrl () {
const local = 'ws://localhost:3000/websocket'
const prod = 'produrl/websocket'
let url = local
if (process.env.NODE_ENV === 'production') url = prod
// https://webpack.js.org/plugins/define-plugin/
// Note that because the plugin does a direct text replacement,
// the value given to it must include actual quotes inside of the string itself.
// Typically, this is done either with either alternate quotes,
// such as '"production"', or by using JSON.stringify('production').
return JSON.stringify(url)
}
function getRESTUrl () {
const local = 'http://localhost:3000'
const prod = 'produrl'
let url = local
if (process.env.NODE_ENV === 'production') url = prod
// https://webpack.js.org/plugins/define-plugin/
// Note that because the plugin does a direct text replacement,
// the value given to it must include actual quotes inside of the string itself.
// Typically, this is done either with either alternate quotes,
// such as '"production"', or by using JSON.stringify('production').
return JSON.stringify(url)
}
Your problem is that you are including the devtool: 'eval-source-map' even when you run webpack production command. This will include the sourcemaps inside your final bundle. So, to remove it, you can do the following:
var config = {
//... you config here
// Remove devtool and devServer server options from here
}
if(process.env.NODE_ENV === 'production') { //Prod
config.plugins.push(
new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify('production')}),
new OptimizeCSSAssets(),
/* The comments: false will remove the license comments of your libs
and you will obtain a real single line file as output */
new webpack.optimize.UglifyJsPlugin({output: {comments: false}}),
);
} else { //Dev
config.devServer = {
contentBase: path.resolve(__dirname, './public'),
historyApiFallback: true,
inline: true,
open: true
};
config.devtool = 'eval-source-map';
}
module.exports = config
I'm using Vue.js to make an SPA application with Django and I transpile, uglify, and bundle the code using webpack (specifically webpack-simple from vue-cli setup).
I use the following to "watch" and hot-reload the code:
$ ./node_modules/.bin/webpack --config webpack.config.js --watch
The problem is every time I change the code and it gets built it generates a new bundle .js file and updates webpack-stats.json to point to that one, but doesn't delete the old ones. How do I have it delete the old (useless) files?
webpack.config.js:
var path = require("path")
var webpack = require('webpack')
var BundleTracker = require('webpack-bundle-tracker')
function resolve (dir) {
return path.join(__dirname, dir)
}
module.exports = {
context: __dirname,
// entry point of our app.
// assets/js/index.js should require other js modules and dependencies it needs
entry: './src/main',
output: {
path: path.resolve('./static/bundles/'),
filename: "[name]-[hash].js",
},
plugins: [
new BundleTracker({filename: './webpack-stats.json'}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
}),
],
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader'}, // to transform JSX into JS
{test: /\.vue$/, loader: 'vue-loader'}
],
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'#': resolve('src')
}
},
}
webpack-stats.json:
{
"status":"done",
"chunks":{
"main":[
{
"name":"main-faa72a69b29c1decd182.js",
"path":"/Users/me/Code/projectname/static/bundles/main-faa72a69b29c1decd182.js"
}
]
}
}
Also what's a good way to add this to git/source control? Otherwise it changes everytime and I have to add it like so:
$ git add static/bundles/main-XXXXX.js -f
which gets annoying.
Any pointers? Thanks!
You need clean-webpack-plugin github link
First install it:
npm i clean-webpack-plugin --save-dev
Then in webpack.config.js add these lines(I have added comments the lines I added):
var path = require("path")
var webpack = require('webpack')
var BundleTracker = require('webpack-bundle-tracker')
const CleanWebpackPlugin = require('clean-webpack-plugin'); // require clean-webpack-plugin
function resolve (dir) {
return path.join(__dirname, dir)
}
// the path(s) that should be cleaned
let pathsToClean = [
path.resolve('./static/bundles/'), // same as output path
]
// the clean options to use
let cleanOptions = {
root: __dirname,
exclude: [], // add files you wanna exclude here
verbose: true,
dry: false
}
module.exports = {
context: __dirname,
// entry point of our app.
// assets/js/index.js should require other js modules and dependencies it needs
entry: './src/main',
output: {
path: path.resolve('./static/bundles/'),
filename: "[name]-[hash].js",
},
plugins: [
new CleanWebpackPlugin(pathsToClean, cleanOptions), // add clean-webpack to plugins
new BundleTracker({filename: './webpack-stats.json'}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
}),
],
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader'}, // to transform JSX into JS
{test: /\.vue$/, loader: 'vue-loader'}
],
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'#': resolve('src')
}
},
}
And that's it, now every time you will run npm run build, the plugin will delete the static/bundles/ folder then build, so all your previous files will get removed, only new files will be there. It won't remove old files while watching with npm run watch
The current latest version does not need any options passed in for most cases. Consult the documentation for more specifics https://www.npmjs.com/package/clean-webpack-plugin
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const webpackConfig = {
plugins: [
/**
* All files inside webpack's output.path directory will be removed once, but the
* directory itself will not be. If using webpack 4+'s default configuration,
* everything under <PROJECT_DIR>/dist/ will be removed.
* Use cleanOnceBeforeBuildPatterns to override this behavior.
*
* During rebuilds, all webpack assets that are not used anymore
* will be removed automatically.
*
* See `Options and Defaults` for information
*/
new CleanWebpackPlugin(),
],
};
module.exports = webpackConfig;
You should adjust webpack so a new bundle is only being created when actually building for production.
From the webpack-simple vue-cli template, you'll see that uglifying and minifying only take place when it is set to a production env, not a dev env:
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
I'm writing ES6 code and transpile it to ES5 with Babel, then minify with Uglify. All run with webpack via gulp. I would like to use external source maps (to keep filesize as small as possible).
The gulp task is pretty basic - all the funky stuff is in the webpack config:
var gulp = require("gulp");
var webpack = require("gulp-webpack");
gulp.task("js:es6", function () {
return gulp.src(path.join(__dirname, "PTH", "TO", "SRC", "index.js"))
.pipe(webpack(require("./webpack.config.js")))
.pipe(gulp.dest(path.join(__dirname, "PTH", "TO", "DEST")));
});
webpack.config.js:
var path = require("path");
var webpack = require("webpack");
module.exports = {
output: {
filename: "main.js",
sourceMapFilename: "main.js.map"
},
devtool: "#inline-source-map",
module: {
loaders: [
{ test: path.join(__dirname, "PTH", "TO", "SRC"),
loader: "babel-loader" }
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
output: {
comments: false,
semicolons: true
},
sourceMap: true
})
]
};
The above works and it creates working source maps - but they are inline.
If I change webpack.config.js so that it says devtool: "#source-map", the source map is created as a separate file (using sourceMapFilename as filename). But it isn't usable - Chrome dev tools doesn't seem to understand it. If I remove the webpack.optimize.UglifyJsPlugin the source map is usable - but the code is not minified. So source map works for the two individual steps, but not when they are run in sequence.
I suspect the uglify step ignores the external sourcemap from the previous transpiler step, so the sourcemap it generates is based on the stream, which of course doesn't exist outside of gulp. Hence the unusable source map.
I'm pretty new to webpack so I may be missing something obvious.
What I'm trying to do is similar to this question, but with webpack instead of browserify: Gulp + browserify + 6to5 + source maps
Thanks in advance.
I highly recommend putting your webpack config inside the gulpfile, or at least make it a function. This has some nice benefits, such as being able to reuse it for different tasks, but with different options.
I also recommend using webpack directly instead of using gulp-webpack (especially if it's the only thing you're piping through). This will give much more predictable results, in my experience. With the following configuration, source maps work fine for me even when UglifyJS is used:
"use strict";
var path = require("path");
var gulp = require("gulp");
var gutil = require("gulp-util");
var webpack = require("webpack");
function buildJs (options, callback) {
var plugins = options.minify ? [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
},
output: {
comments: false,
semicolons: true,
},
}),
] : [];
webpack({
entry: path.join(__dirname, "src", "index.js"),
bail: !options.watch,
watch: options.watch,
devtool: "source-map",
plugins: plugins,
output: {
path: path.join(__dirname, "dist"),
filename: "index.js",
},
module: {
loaders: [{
loader: "babel-loader",
test: /\.js$/,
include: [
path.join(__dirname, "src"),
],
}],
},
}, function (error, stats) {
if ( error ) {
var pluginError = new gutil.PluginError("webpack", error);
if ( callback ) {
callback(pluginError);
} else {
gutil.log("[webpack]", pluginError);
}
return;
}
gutil.log("[webpack]", stats.toString());
if (callback) { callback(); }
});
}
gulp.task("js:es6", function (callback) {
buildJs({ watch: false, minify: false }, callback);
});
gulp.task("js:es6:minify", function (callback) {
buildJs({ watch: false, minify: true }, callback);
});
gulp.task("watch", function () {
buildJs({ watch: true, minify: false });
});
I would recommend using webpack's devtool: 'source-map'
Here's an example webpack.config with source mapping below:
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'source-map',
entry: ['./index'],
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'public'),
publicPath: '/public/'
},
module: {
loaders: [
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }
]
},
plugins: [
]
};