So my app is running off a concatenated admin.bundle.js file. I'm using webpack to manage the modules, and then using gulp-webpack to import my webpack config, then run the sourcemap code:
gulp.task('webpack', function() {
return gulp.src('entry.js')
.pipe(webpack( require('./webpack.config.js') ))
.pipe(sourcemaps.init())
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('app/assets/js'));
});
My Webpack config
var webpack = require('webpack');
module.exports = {
entry: "./entry.js",
output: {
pathinfo: true,
path: __dirname,
filename: "admin.bundle.js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style!css" }
]
}
};
The problem is when I'm testing my app with ChromeDev tools, the break points in the individual app modules won't work. They only work when I look at the source for admin.bundle.js this isn't ideal as I need to search for a specific line in the code to goto :( instead of just having the break point happen inside of the module itself, which makes it easier and faster to debug.
Below the debugger is stopped on a function inside of the concatenated admin.bundle.js file
There is the tagsDirective.js module, this is where I expect the break point to happen :(
Anyone run into this problem before with Webpack and Gulp?
Screenshot of part of the admin.bundle and the map file:
Ah figured it out, I moved the sourcemap generation code back into webpack, and out of Gulp:
var webpack = require('webpack');
var PROD = JSON.parse(process.env.PROD_DEV || '0');
module.exports = {
entry: "./entry.js",
devtool: "source-map",
output: {
devtoolLineToLine: true,
sourceMapFilename: "admin.bundle.js.map",
pathinfo: true,
path: __dirname,
filename: PROD ? "admin.bundle.min.js" : "admin.bundle.js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style!css" }
]
},
plugins: PROD ? [
new webpack.optimize.UglifyJsPlugin({minimize: true})
] : []
};
gulp.task('webpack', function() {
return gulp.src('entry.js')
.pipe(webpack( require('./webpack.config.js') ))
// .pipe(sourcemaps.init())
// .pipe(sourcemaps.write('./'))
.pipe(gulp.dest('app/assets/js'));
});
Related
(webpack.config.js file content below)
I'm trying to make a webpack exclusion on node modules.
I found that using webpack-node-externals works for it but using that on my common config causes this other error:
Require is not defined on reflect-metadata - __webpack_require__ issue
So... I was wondering how can i exclude webpack bundling also on the browser side without getting any issue.
My webpack version: 3.11.0
webpack-config.js
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AotPlugin = require('#ngtools/webpack').AotPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
var nodeExternals = require('webpack-node-externals');
module.exports = (env) => {
// Configuration in common to both client-side and server-side bundles
const isDevBuild = !(env && env.prod);
const sharedConfig = {
//externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
stats: { modules: false },
context: __dirname,
resolve: { extensions: [ '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /\.ts$/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader', 'angular2-router-loader'] : '#ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: [ 'to-string-loader', 'style-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
]
},
plugins: [new CheckerPlugin()]
};
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot.browser.ts' },
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.browser.module#AppModule'),
exclude: ['./**/*.server.ts']
})
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverBundleConfig = merge(sharedConfig, {
resolve: { mainFields: ['main'] },
entry: { 'main-server': './ClientApp/boot.server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
})
].concat(isDevBuild ? [] : [
// Plugins that apply in production builds only
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.server.module#AppModule'),
exclude: ['./**/*.browser.ts']
})
]),
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder,
devtool: 'inline-source-map'
});
return [clientBundleConfig, serverBundleConfig];
};
GOT IT!
Before posting my solution, I'd like to thanks Aluan Haddad for his useful comment in my question above.
As suggested by Aluan, in fact, the problem was related to the need to use also a module loader, more than a module bundler.
So, the steps that I followed are these:
Installing requireJS ==> http://requirejs.org/docs/node.html
Removing externals: [nodeExternals()], // in order to ignore all modules in node_modules folder from my common webpack configuration and adding it under my server configuration (done before my question, but it's a really important step) [see webpack.config.js content in the question]
Adding target: 'node', before my externals point above, under my server side section (done before my question, but it's a really important step) [see webpack.config.js content in the question]
This makes sure that browser side keeps target:'web' (default target), and target becomes node just for the server.
launched webpack config vendor command manually from powershell webpack --config webpack.config.vendor.js
launched webpack config command manually from powershell webpack --config webpack.config.js
That worked for me! Hope It will works also for anyone else reading this question and encountering this issue!
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 have created a project using react and flux architecture. Need to chunk the bundle.js file because by combining all the files it is creating a huge js file of 4mb which is causing problem in downloading on slow network so how to chunk the js file so that only the required libraries are included when a page opens
I am using webpack 1.x
my directory structure is
webpack.config.js file
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'cheap-module-source-map',
entry: [
'./src/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: ''
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.optimize.CommonsChunkPlugin({
// names: ["app", "subPageA"]
// (choose the chunks, or omit for all chunks)
children: true,
// (use all children of the chunk)
async: true,
// (create an async commons chunk)
// minChunks: 3,
// (3 children must share the module before it's separated)
})
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['react-hot', 'babel'],
include: path.join(__dirname, 'src')
}, {
test: /\.css$/,
exclude: /\.useable\.css$/,
loader: "style-loader!css-loader"
}, {
test: /\.useable\.css$/,
loader: "style-loader/useable!css-loader"
}, {
test: /\.png$/,
loaders: ["url-loader?mimetype=image/png"]
}, {
test: /\.(png|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000'
}]
}
};
server.js file
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true
}).listen(3000, 'localhost', function(err, result) {
if (err) {
return console.log(err);
}
console.log('Listening at http://localhost:3000/');
});
index.html file
<html>
<head>
<title>Project</title>
</head>
<body>
<div id="app" />
<script src="bundle.js" type="text/javascript"></script>
</body>
</html>
When you need a particular module, that is not required on the initial load you can use
require.ensure(["module-a", "module-b"], function() {
var a = require("module-a");
// ...
});
That way it only gets loaded when you need it, thus decreasing your bundle size.
If you use routes and react-router you can use per route code splitting as described in this article
http://moduscreate.com/code-splitting-for-react-router-with-es6-imports/
Im my experience, typically with webpack-optimize-chunk-plugin, you split your projects code into a vendor.js and a bundle.js. like this:
module.exports = {
entry:{
vendor: ["react", "react-dom"], // list all vender libraries here
app: ['./path/to/entry.js']
},
output: {
path: path.join(__dirname, './public'),
filename:'bundle.js'
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js")
]
}
So this would output a bundle.js and a vendor.js. I haven't seen webpack-optimize-chunk-plugin used in the way you described. (it would be very cool if possible).
Also I would check out all the other webpack optimization plugins to also help with the over all file size. (i.e. DedupePlugin, UglifyJsPlugin, OccurenceOrderPlugin...). More info here. Also here is an example of multi entry point that you may find helpful. Best of luck.
I am trying to use webpack as a replacement for gulp and livereload workflow. I have set up HotModuleReplacement Plugin and it works correctly for JS files but I can't get it to work with SCSS files. It is compiling the SCSS to CSS properly but I have to manually refresh the browser each time to get the style changes to show. I am thinking it maybe a mistake in how I have the config set up or something like that.
I have this server.js file that is running things:
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true,
noInfo: true,
stats: { colors: true }
}).listen(3000, 'localhost', function (err, result) {
if (err) {
console.log(err);
}
console.log('Listening at localhost:3000');
});
and this webpack.config.js
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var cssLoaders = ['css-loader'];
var jsLoaders = ['react-hot', 'babel'];
var scssLoaders = cssLoaders.slice(0);
scssLoaders.push('sass-loader?includePaths[]=' + path.resolve(__dirname, './styles'));
module.exports = {
devtool: 'sourcemap',
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./scripts/index'
],
output: {
path: path.join(__dirname, './build'),
filename: 'bundle.js',
publicPath: '/build/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new ExtractTextPlugin('styles.css')
],
resolve: {
extensions: ['', '.js', '.jsx', '.scss']
},
module: {
loaders: [
{ test: /\.js?$/, loaders: jsLoaders, include: path.join(__dirname, 'scripts'), exclude: /node_modules/},
{ test: /\.css$/ ,loader: ExtractTextPlugin.extract('style-loader', cssLoaders.join('!')) },
{ test: /\.js$/, loader: "eslint-loader", exclude: /node_modules/ },
{ test: /\.scss$/, loader: ExtractTextPlugin.extract('style-loader', scssLoaders.join('!')) }
]
}
};
In one of my js files I just have a call to the SCSS file like this:
require('../styles/app');
I have looked into the docs for this and there are some instructions that suggest that you need to manually opt in for each module but I am not sure why that is, where to add that code etc
What I am trying to do seems like a pretty straight forward use case so is this supported or will I still also have to use gulp and live reload just for styles?
Unfortunately the extract-text-webpack-plugin, which is extracting all your styles to a CSS file, doesn't work well with hot-reloading (see https://github.com/webpack/extract-text-webpack-plugin/issues/30).
This hacky bit of JavaScript will reload all stylesheets any time it detects any hot reload event happening. It can get annoying, though, and works better on Firefox than on Chrome - Chrome seems to delay applying the new stylesheet until you focus the browser tab.
if (module.hot) {
$(window).on("message onmessage", function(event) {
if (typeof event.originalEvent.data === "string" && event.originalEvent.data.indexOf("webpackHotUpdate") === 0) {
console.log("Reloading style sheets...");
document.styleSheets.forEach(function (sheet) {
if ((sheet.href || "").indexOf('localhost') !== -1) {
sheet.ownerNode.href = sheet.href;
}
});
}
});
}
There may be some way to hook further into the guts of the hot reloading code, but I haven't looked into it.
As mentioned above, extract-text-webpack-plugin is not working properly with hot replacement, unfortunately :( But there's one more option how to solve this issue while development. That's disable property in extract plugin settings.
Modify a bit your config as described below:
plugins: [
new ExtractTextPlugin('styles.css', {disable: process.env.NODE_ENV !== 'production'})
]
That will disable usage of ExtractTextPlugin while development (I mean if you run it anyhow but NODE_ENV=production webpack, or any other rule you prefer) and bundle your styles within js.
Also mind importing your style file in the entry point. Hope that works. Cheers ;)
PS. Also you can avoid combining your entry point with 'webpack-dev-server/client?http://localhost:3000', 'webpack/hot/only-dev-server' and adding new webpack.HotModuleReplacementPlugin() to plugins manually just by running webpack dev server with additional params
webpack-dev-server --inline --hot
inline stands for webpack-dev-server/client and --hot for webpack-dev-server/client
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: [
]
};