Source mapping with webpack for express server - javascript

I have an express server that is written in es5 and es6 combined. It consists of js and ts files. So now when I make a webpack build and start the server, it runs fine. But if my code throws an error then the error tracing is not correct i.e source of error (file, line and column number) is not showing correctly.
Is there a way to map the bundle with the source?
I have tried adding:
devTool: "source-map" to webpack config but it doesn't work, it seems to be working with the browser. Is there any way to achieve the same for server-side as well?
Here is my webpack.config.js
const nodeExternals = require("webpack-node-externals");
const webpack = require("webpack");
const path = require("path");
module.exports = {
stats: "detailed",
target: "node",
externals: [nodeExternals()],
entry: {
app: "./server.js",
backupCronApp: "./backup/cron/index.js"
},
output: {
path: path.join(__dirname, "/build"),
filename: "[name].js",
libraryTarget: "commonjs2",
},
plugins: [new webpack.EnvironmentPlugin(["NODE_ENV"])],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: "babel-loader",
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.ts', '.js'],
},
};

Related

Independent chunk files with webpack

I am building a component library and I am using Webpack to bundle it. Some components only rely on html templates, css and JavaScript that I've written, but some components require external libraries.
What I'd like to achieve is a vendor.js that is optional to include if the component you want to use needs it.
For instance, If a user only needs a component without vendor dependencies, it would suffice that they use main.bundle.js which only contains my own code.
In my index.js, I have the following imports:
import { Header } from './components/header/header.component';
import { Logotype } from './components/logotype/logotype.component';
import { Card } from './components/card/card.component';
import { NavigationCard } from './components/navigation-card/navigation-card.component';
import { AbstractComponent } from './components/base/component.abstract';
import { Configuration } from './system.config';
import 'bootstrap-table';
import './scss/base.scss';
All of these imports are my own, expect for bootstrap-table.
I have configured Webpack like this:
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractScss = new ExtractTextPlugin({
filename: "[name].bundle.css"
});
module.exports = {
entry: {
main: './src/index.ts'
},
output: {
path: path.resolve(__dirname, 'dist/release'),
filename: "[name].bundle.js",
chunkFilename: "[name].bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor', // Specify the common bundle's name.
minChunks: function (module) {
// Here I would like to tell Webpack to give
// each bundle the ability to run independently
return module.context && module.context.indexOf('node_modules') >= 0;
}
}),
extractScss
],
devtool: "source-map",
resolve: {
// Add `.ts` as a resolvable extension.
extensions: ['.webpack.js', '.web.js', '.ts', '.js', '.ejs']
},
module: {
rules: [
// All files with a '.ts' extension will be handled by 'awesome-typescript-loader'.
{ test: /\.ts?$/, exclude: /node_modules/, loader: "awesome-typescript-loader" },
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" },
// Allows for templates in separate ejs files
{test: /\.ejs$/, loader: 'ejs-compiled-loader'},
{
test: /\.scss$/,
use: extractScss.extract({
use: [{
loader: 'css-loader', options: {
sourceMap: true
}
}, {
loader: 'sass-loader', options: {
soureMap: true
}
}]
})}
]
}
}
This results in two .js files and one .css. However, webpacks common module loading functionality resides in vendor.js, and that renders my main unusable if I don't include vendor first, and it isn't always needed.
To sum it up, if a user only needs the footer (no external dependencies), this would suffice:
<script src="main.bundle.js"></script>
If the user wants to use the table, which has an external dependency, they would need to include both:
<script src="vendor.js"></script>
<script src="main.bundle.js"></script>
Right now, including only main.bundle.js gives me this error:
Uncaught ReferenceError: webpackJsonp is not defined.
I am aware that I can extract all common functionality by adding this after my vendor chunk is created in the Webpack config:
new webpack.optimize.CommonsChunkPlugin({
name: 'common'
})
But this approach still requires the user to include two .js files.
How can I go about achieving this? It seems that it only differs 2 kb when I don't extract the common modules like I do above, and that is fine with me.
Turns out this is very easy to do if you can stand some manual work and actually understand what Webpack does (which I didn't). I solved it like this:
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractScss = new ExtractTextPlugin({
filename: "[name].bundle.css"
});
module.exports = {
entry: {
main: './src/index.ts',
vendor: './src/vendor/vendor.ts'
},
output: {
path: path.resolve(__dirname, 'dist/release'),
filename: "[name].bundle.js",
chunkFilename: "[name].bundle.js"
},
plugins: [
extractScss
],
devtool: "source-map",
resolve: {
// Add `.ts` as a resolvable extension.
extensions: ['.webpack.js', '.web.js', '.ts', '.js', '.ejs']
},
module: {
rules: [
// All files with a '.ts' extension will be handled by 'awesome-typescript-loader'.
{ test: /\.ts?$/, exclude: /node_modules/, loader: "awesome-typescript-loader" },
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" },
// Allows for templates in separate ejs files
{test: /\.ejs$/, loader: 'ejs-compiled-loader'},
{
test: /\.scss$/,
use: extractScss.extract({
use: [{
loader: 'css-loader', options: {
sourceMap: true
}
}, {
loader: 'sass-loader', options: {
soureMap: true
}
}]
})}
]
}
}
In vendor.ts, I then simply import any vendor dependencies I have:
import 'jquery';
import 'bootstrap-table';
This results in two different files, both have Webpacks bootstrapping logic.
Hope this helps someone.

Webpack dev server - Not allowed to load local resource

I'm using webpack-dev-server in order to develop a React app on windows.
When running the command: webpack-dev-server --config webpack/webpack.dev.js,
then going to localhost, I'm getting an error message for the js file (the bundled one):
Not allowed to load local resource: file:///C:/Dev/react-starter/dist/main.js
I'm not fully familiar with webpack-dev-server, but didn't get a sense about why this can happen even from the docs and the GH issues.
my config looks like:
var path = require('path');
var WebpackDashboard = require('webpack-dashboard');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var srcFolder = path.resolve(__dirname, '../src');
var buildFolder = path.resolve(__dirname, '../dist');
var publicFolder = path.resolve(__dirname, '../assets');
module.exports = {
target: 'web',
entry: './index.js',
context: srcFolder,
devtool: 'source-map',
output: {
path: buildFolder,
publicPath: path.resolve(__dirname, '../dist/'),
filename: '[name].js',
chunkFilename: '[name].chunk.js',
},
resolve: {
extensions: ['.js', '.jsx', '.json', '.scss'],
alias: {
'#': srcFolder,
}
},
module: {
rules: [
{
test: /\.(js|jsx)/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.scss$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{ loader: 'sass-loader' },
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
inject: 'body',
template: path.resolve(__dirname, '../src/index.html'),
}),
],
devServer: {
contentBase: path.join(__dirname, '../dist'),
port: 4464,
hot: true,
publicPath: buildFolder,
}
}
Hope someone can help. Tnx!
I got the same problem today, and I think I know where is the problem. It's the publicPath. When we have this value, the script tag in html file should be updated accordingly, but it seems like it's not easy to change something auto-generated by HtmlWebpackPlugin.
So easy fix is delete the publicPath value. Works for me.
I also got the same problem today. My solution is to move/copy the local resource to the public folder. After doing so, I also updated the path that references that resource accordingly in the js/html file to //<resource_name>.
It does not require to modify the webpack config. Hope it helps!^_^

Webpack file-loader not exporting images

I am using webpack for my PHP and React project. I want to load a background image from my .scss file with the webpack file-loader but for some reason I don't know, the img-folder does not get copied/exported to my dist-folder. Below is the webpack.config.js:
var webpack = require("webpack");
var path = require("path");
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var WatchLiveReloadPlugin = require('webpack-watch-livereload-plugin');
var DIST_DIR = path.resolve(__dirname, "dist");
var SRC_DIR = path.resolve(__dirname, "src");
var extractPlugin = new ExtractTextPlugin({
filename: 'main.css'
});
module.exports = {
entry: ['babel-polyfill', SRC_DIR + "/app/index.js"],
output: {
path: DIST_DIR + "/app",
filename: "bundle.js",
publicPath: "/dist"
},
watch: true,
module: {
rules: [
{
test: /\.js$/,
include: SRC_DIR,
loader: "babel-loader",
exclude: /node_modules/,
query: {
presets: ["react", "es2015", "stage-2"], plugins: ["transform-decorators-legacy", "transform-class-properties"]
}
},
{
test: /\.scss$/,
use: extractPlugin.extract({
fallback: "style-loader",
use: ["css-loader", "sass-loader", "resolve-url-loader"]
})
},
{
test: /\.css$/,
use: ["css-loader", "sass-loader", "resolve-url-loader"]
},
{
test: /\.(jpg|png)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'img/',
publicPath: 'img/'
}
}
]
}
]
},
plugins: [
extractPlugin,
new WatchLiveReloadPlugin({
port: 'localhost',
files: [
'./dist/app/*.css',
'./dist/**/*.js',
'./src/app/**/*.png',
'./src/app/**/*.jpg',
'./src/app/**/.*.scss',
'./src/**/*.php',
'./src//*.js'
]
})
]
};
I also tried loader: 'file-loader?name=/dist/img/[name].[ext]', but with no luck.
My file structure is like this:
-- dist
-- app
bundle.js
main.css
-- src
-- app
-- css
main.scss
-- img
someimage.jpg
Then in my .scss i tried this:
background-image: url('/img/someimage.jpg');
Does anyone have an idea what's wrong here?
Try to import the image file in one of your script files like
import '/path/to/img.jpg';
this will let Webpack know about the dependency and copy it.
The CSS/Sass loaders do not translate URLs that start with a /, therefore your file-loader won't be applied here.
The solution is to use relative paths for the imports if you want them to be processed by webpack. Note that CSS and Sass have no special syntax for relative imports, so the following are equivalent:
url('img/someimage.jpg')
url('./img/someimage.jpg')
If you want them to be resolved just like a module, webpack offers the possibility to start the import path with a ~, as shown in sass-loader - imports.

How to add header comments to webpack uglified JavaScript?

I am currently using the following webpack.config.js:
var webpack = require('webpack');
module.exports = {
entry: __dirname + "/src/index.js",
output: {
path: __dirname,
filename: "index.js"
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
exclude: '/node_modules/',
query: {
presets: ['latest']
}
}
]
},
plugins: [ new webpack.optimize.UglifyJsPlugin({minimize: true}) ]
}
This works exactly how I want it to. But now I want to add some comments with project info to the output file, on top of the one line with uglified code. How do I do this?
Add the comments to the code after minification using Webpack's BannerPlugin():
const webpack = require('webpack');
new webpack.BannerPlugin(banner);
// or
new webpack.BannerPlugin(options);

webpack-dev-server watches and compiles files correctly, but browser can't access them

EDIT: Link to github repo where this example is hosted is here in case someone wants to run it
I'm getting the near exact same problem as another user (you can find the question here), in that running the webpack-dev-server does actually compile and watch files correctly (seeing the console output in the terminal), but the browser still can't view my site correctly. This is my webpack.config.js file:
var webpack = require('webpack'),
path = require('path'),
// webpack plugins
CopyWebpackPlugin = require('copy-webpack-plugin');
var config = {
context: path.join(__dirname,'app'),
entry: './index.js',
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js',
publicPath: path.join(__dirname, 'public')
},
devServer: {
// contentBase: './public/'
},
plugins: [
// copies html to public directory
new CopyWebpackPlugin([
{ from: path.join(__dirname, 'app', 'index.html'),
to: path.join(__dirname, 'public')}
]),
// required bugfix for current webpack version
new webpack.OldWatchingPlugin()
],
module: {
loaders: [
// uses babel-loader which allows usage of ECMAScript 6 (requires installing babel-preset-es2015)
{test: /\.js$/, loader: 'babel', exclude: /node_modules/, query: { presets: ['es2015']}},
// uses the css-loader (loads css content) and style-loader (inserts css from css-loader into html)
{test: /\.css$/, loader: 'style!css', exclude: /node_modules/}
]
}
};
module.exports = config;
And this is my directory structure:
+--- webpack/
+--- app/
+--- index.html
+--- index.js
+--- styles.css
+--- package.json
+--- webpack.config.js
Currently, running webpack-dev-server outputs the following in the browser (note the lack of the public/ directory which is where webpack normally outputs my html and javascript bundle):
EDIT: Adding the devServer.contentBase property and setting it to public gets the browser to return a 403 error not found as shown here:
Okay, so I was able to reproduce the issue that you have on my project. To fix the issue I changed some things.
Here is what I have set up. I'm defining a bit less in the output and using jsx instead of js, but the results should be the same. You can replace my src with wherever your source code is.
const config = {
entry: './src/App.jsx',
output: {
filename: 'app.js'
},
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react', 'stage-0'],
plugins: ['add-module-exports']
}
},
{
include: /\.json$/, loaders: ['json-loader']
},
{
test: /\.scss$/,
loaders: ['style', 'css?modules', 'sass']
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
loader: 'file?name=fonts/[name].[ext]'
}
]
},
plugins: [
new webpack.ProvidePlugin({
'Promise': 'exports?module.exports.Promise!es6-promise',
'fetch': 'imports?self=>global!exports?global.fetch!isomorphic-fetch'
}),
new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
})
],
resolve: {
root: path.resolve('./src')
},
devServer: {
contentBase: 'src'
}
};
So basically you would want this output in terminal:
webpack result is served from / - tells us that whatever we build from will be at the root
content is served from src - tells us that it's building from that directory
Hope this helps

Categories

Resources