How to get sourcemaps working for React Css Modules? - reactjs

I'm trying to setup a React project with react-css-modules, webpack and Hot Module Replacement. Everything is working like a charm but I can't get the CSS sourcemaps to work.
I followed this guide to make HMR work. It involves a BrowserSync setup to update the css file after Webpack writes it to disk.
I use (as suggested by react-css-modules) the ExtractTextPlugin to extract all of the css:
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style','css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass')
}
But if I change this to sourcemaps, as suggested here
loader: ExtractTextPlugin.extract('style', 'css?sourceMap!sass-loader outputStyle=expanded&sourceMap=true&sourceMapContents=true')
I get the error: "root" CSS module is undefined. in my browser console.
You can find my example repo here, but here's the full webpack config I'm using for development.
var webpack = require('webpack');
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var WriteFilePlugin = require('write-file-webpack-plugin').default;
module.exports = {
entry: {
bundle: [
'webpack/hot/dev-server',
'webpack-hot-middleware/client',
'./index.js'
]
},
devtool: 'cheap-module-source-map',
debug: true,
devServer: devServer,
context: path.resolve(__dirname, './src'),
output: {
path: path.resolve(__dirname, './builds'),
filename: '[name].js',
publicPath: '/builds/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.OldWatchingPlugin(),
new WriteFilePlugin(),
new ExtractTextPlugin('[name].css', {
allChunks: true
})
],
module: {
loaders: [
{
test: /\.js$/,
loaders: ['react-hot', 'babel-loader'],
exclude: /node_modules/
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style','css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass')
}
]
},
resolve: {
extensions: ['', '.js', '.json']
}
};
How to make the sourcemap work?

Use this:
ExtractTextPlugin.extract('style','css?sourceMap&modules&importLoaders=1&localI‌​dentName=[name]__[local]___[hash:base64:5]!sass?sourceMap')
i.e. add the sourceMap param to both css & sass loaders. It said so in sass-loader docs.

This is how I have my css modules set up:
'css-loader?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!',

Related

ts-loader with sass-loader & ExtractTextPlugin

This topic could be considered as a continuation of my previous question related to webpack & ts-loader
Now I am trying to understand how to use sass-loader with ts-loader and ExtractTextPlugin. After hours of digging it seems that ExtractTextPlugin is parsing node_modules and hence fails.
In the code example below you can see the commented part (the old style loader part) and new one which I'm trying to make work with guidance from sass-loader docs.
Currently I am stuck on this (and dozens of other similar parsing issues from node_modules):
webpack.config.js
const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin"); // <-- as soon as this is imported, the build fails
const extractSass = new ExtractTextPlugin({
filename: "[name].[contenthash].css",
disable: process.env.NODE_ENV === "development"
});
module.exports = env => {
return {
devtool: "inline-source-map",
entry: "./src/index.tsx",
output: {
path: path.resolve(__dirname, "/public"),
filename: "build/app.js"
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".json", ".scss"],
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: path.resolve(__dirname, "/node_modules"),
loader: "ts-loader",
},
{
test: /\.scss$/,
exclude: path.resolve(__dirname, "/node_modules"),
use: extractSass.extract({
use: [
{
loader: "style-loader",
exclude: path.resolve(__dirname, "/node_modules")},
{
loader: "css-loader",
exclude: path.resolve(__dirname, "/node_modules")},
{
loader: "sass-loader",
exclude: path.resolve(__dirname, "/node_modules"),
options: {
includePaths: [path.resolve(__dirname, "/src")],
}
},
],
}),
}
// {
// test: /\.scss$/,
// loader: 'style-loader!css-loader!sass-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
// }
],
},
plugins: [
extractSass,
]
}
}
N.B. Without ExtractTextPlugin I get an empty object when importing .scss into a .tsx file. So if you can help me solve also this issue, I would be glad (and able to continue coding) :)
import * as styles from "./Main.scss"; // <-- styles is {/* empty object */}

Webpack production build file paths are off

I'm running this command to try & generate a production webpack build:
rimraf ./build/* && webpack -p --progress --config webpack.production.js
However, when I open up the build/index.html, it's failing to load a lot of files because the locations are off.
It fails to put the correct location for the bundle.js file. It loads it like this: /bundle.js. However the bundle.js file is actually in the same directory as the index.html file in the build folder so it should load it like this ./bundle.js
If I correct the bundle.js path, it's still putting an incorrect route for the assets:
What's interesting is that my app currently works with the webpack dev server when I run: webpack-dev-server --inline --progress --config webpack.dev.js.
Here is what my current webpack.production.js file looks like:
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'source-map',
devServer: {
historyApiFallback: true, // This will make the server understand "/some-link" routs instead of "/#/some-link"
},
entry: [
'./src/scripts' // This is where Webpack will be looking for the entry index.js file
],
output: {
path: path.join(__dirname, 'build'), // This is used to specify folder for producion bundle
filename: 'bundle.js', // Filename for production bundle
publicPath: '/'
},
resolve: {
modules: [
'node_modules',
'src',
path.resolve(__dirname, 'src/scripts'),
path.resolve(__dirname, 'node_modules')
], // Folders where Webpack is going to look for files to bundle together
extensions: ['.jsx', '.js'] // Extensions that Webpack is going to expect
},
module: {
// Loaders allow you to preprocess files as you require() or “load” them.
// Loaders are kind of like “tasks” in other build tools, and provide a powerful way to handle frontend build steps.
loaders: [
{
test: /\.jsx?$/, // Here we're going to use JS for react components but including JSX in case this extension is preferable
include: [
path.resolve(__dirname, "src"),
],
loader: ['react-hot-loader']
},
{
loader: "babel-loader",
// Skip any files outside of your project's `src` directory
include: [
path.resolve(__dirname, "src"),
],
// Only run `.js` and `.jsx` files through Babel
test: /\.jsx?$/,
// Options to configure babel with
query: {
plugins: ['transform-runtime'],
presets: ['es2015', 'stage-0', 'react'],
}
},
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader']
}
]
},
plugins: [
new webpack.NoEmitOnErrorsPlugin(), // Webpack will let you know if there are any errors
// Declare global variables
new webpack.ProvidePlugin({
React: 'react',
ReactDOM: 'react-dom',
_: 'lodash'
}),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './src/index.html',
hash: true
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
}),
]
}
And just in case, this is what my current webpack.dev.js file looks like:
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'cheap-module-source-map',
devServer: {
historyApiFallback: true, // This will make the server understand "/some-link" routs instead of "/#/some-link"
},
entry: [
'babel-polyfill',
'webpack-dev-server/client?http://127.0.0.1:8080/', // Specify the local server port
'webpack/hot/only-dev-server', // Enable hot reloading
'./src/scripts' // This is where Webpack will be looking for the entry index.js file
],
output: {
path: path.join(__dirname, 'build'), // This is used to specify folder for producion bundle
filename: 'bundle.js', // Filename for production bundle
publicPath: '/'
},
resolve: {
modules: [
'node_modules',
'src',
path.resolve(__dirname, 'src/scripts'),
path.resolve(__dirname, 'node_modules')
], // Folders where Webpack is going to look for files to bundle together
extensions: ['.jsx', '.js'] // Extensions that Webpack is going to expect
},
module: {
// Loaders allow you to preprocess files as you require() or “load” them.
// Loaders are kind of like “tasks” in other build tools, and provide a powerful way to handle frontend build steps.
loaders: [
{
test: /\.jsx?$/, // Here we're going to use JS for react components but including JSX in case this extension is preferable
include: [
path.resolve(__dirname, "src"),
],
loader: ['react-hot-loader']
},
{
loader: "babel-loader",
// Skip any files outside of your project's `src` directory
include: [
path.resolve(__dirname, "src"),
],
// Only run `.js` and `.jsx` files through Babel
test: /\.jsx?$/,
// Options to configure babel with
query: {
plugins: ['transform-runtime', 'transform-decorators-legacy'],
presets: ['es2015', 'stage-0', 'react'],
}
},
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader']
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(), // Hot reloading
new webpack.NoEmitOnErrorsPlugin(), // Webpack will let you know if there are any errors
// Declare global variables
new webpack.ProvidePlugin({
React: 'react',
ReactDOM: 'react-dom',
_: 'lodash'
}),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './src/index.html',
hash: false
})
]
}
Any ideas what I'm doing wrong?
faced a similar issue. setting output.publicPath: "/" in webpack.dev.js and output.publicPath: "./" in webpack.prod.js, did the trick for me.
Got the same error when running npm run watch, local dev still worked, but after deploying to demo server the app crashed on wrong js-file url.
Cause:
Some changes in my webpack.mix.js started compiling a index.html file that was found by the browser, instead of the app.blade I was using.
Fixed the paths by setting: publicPath: './public/'
(Note that it's a relative path). Also, I removed the generated url by setting inject: false, in the HtmlWebpackPlugin({ section and used the asset('/...') logic.

Webpack -p doesn't create bundle correctly

I started learning React by myself and I decided to create a boilerplate for me. I'm getting a problem to build a project using webpack. When I run in dev mode, works fine. When I run the command 'postinstall' to build for production, it generates a bundle.js with only a few bytes. But when I run the 'postinstall' without the parameter -p, it generates my bundle with ~ 2MB, the same thing when generates for dev mode (obviously because is not set for production). I didn't figure out why the production flag isn't creating my bundle correct. Can someone help me with this problem?
The project is in the repository:
https://github.com/ribeiroguilherme/react-boilerplate-dashboard
The webpack.production.config.js file:
const webpack = require('webpack');
const path = require('path');
const ExtractPlugin = require('extract-text-webpack-plugin');
const CleanPlugin = require('clean-webpack-plugin');
const plugins = [
new CleanPlugin('dist'),
new ExtractPlugin('bundle.css'),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({ minimize: true }),
new webpack.optimize.AggressiveMergingPlugin(),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
},
}),
];
module.exports = {
devtool: 'eval',
debug: false,
context: __dirname + '/src/client',
entry: {
javascript: './index.jsx',
html: './index.html',
},
output: {
filename: 'bundle.js',
path: __dirname + '/dist',
},
resolve: {
extensions: ['', '.js', '.jsx', '.json'],
root: path.resolve(__dirname, './src/client'),
},
eslint: {
configFile: './.eslintrc',
},
module: {
preLoaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'eslint-loader',
},
],
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loaders: ['babel-loader'],
},
{
test: /\.html$/,
loader: 'file?name=[name].[ext]',
},
{
test: /\.css$/,
loader: ExtractPlugin.extract('style-loader', 'css-loader'),
},
],
},
plugins: plugins,
};
I'm also worried because the bundle looks pretty big for a project that I just started now. Any hints will be very appreciated.
Best Regards

Webpack with babel-loader for react corrupts image files

I am using webpack with babel-loader to transform .jsx react files.
However, adding a file-loader or style- and css-loader does not correctly process the images required() in the react components or style sheets.
They get recognized by webpack and copied to the dist folder. The path to the image file is correct, I've verified this in the css and js output.
The server is also able to display the files, I've checked with some manually copied ones.
What is happening is that the images themselves get corrupted. No image viewer nor the browser can display the image which results in an invisible image in the browser.
What I've tried so far:
using only babel-loader as suggested in: https://github.com/webpack/file-loader/issues/35, results in Error: No handler for file type.
using file-loader directly
using image-webpack-loader (which seems to be using file-loader under the hood)
using IsomorphicLoaderPlugin (https://github.com/jchip/isomorphic-loader) which seems to be a simpler alternative to webpack-isomorphic-tools
using css background-images with url() and ExtractTextPlugin('style-loader", 'css-loader')
All of the above steps resulted in either errors with webpack not finding an appropriate handler or corrupted image files.
Here is my current webpack config for reference (I've included all of it in case there are any problems/conflicts I am overlooking):
var ExtractTextPlugin = require('extract-text-webpack-plugin'),
webpack = require('webpack');
IsomorphicLoaderPlugin = require("isomorphic-loader/lib/webpack-plugin");
module.exports = {
context: __dirname + '/client',
entry: ['babel-polyfill', './index.jsx'],
output: {
filename: 'app.js',
path: __dirname + '/dist',
publicPath: '/'
},
resolve: {
ignore: /node_modules/,
extensions: ['', '.js', '.jsx']
},
devtool: 'source-map',
plugins: [
new ExtractTextPlugin('styles.css'),
new IsomorphicLoaderPlugin({ keepExistingConfig: false }),
new webpack.DefinePlugin({
"process.env": {
BROWSER: JSON.stringify(true)
}
})
],
module: {
preLoaders: [
{
loaders: ['isomorphine']
}
],
loaders: [
{
test: /\.jsx?$/,
loader: 'babel',
exclude: /node_modules/,
query: {
cacheDirectory: true,
plugins: ['transform-runtime', 'transform-decorators-legacy', 'transform-class-properties', 'transform-object-rest-spread'],
presets: ['react', 'es2015', 'stage-0']
}
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loader: "file!isomorphic"
}
]
}
};

Webpack doesn't correctly load my files

I'm totally new to webpack and I'm doing my first configuration for a new project.
I'm trying to load my jsx/scss file but I've this problem:
var path = require('path');
var webpack = require('webpack');
var autoprefixer = require('autoprefixer');
var node_modules_dir = path.resolve(__dirname, 'node_modules');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var HtmlWebpackPlugin = require('html-webpack-plugin');
var cssExtractTextPlugin = new ExtractTextPlugin("css", "index.css");
var staticPrefix = path.join(__dirname, 'src')
var distPath = path.join(__dirname, 'dist')
module.exports = {
devtool: 'eval',
//context: path.join(__dirname, staticPrefix),
entry: {
'app': ['webpack-hot-middleware/client', path.join(__dirname, 'src/app.jsx')],
'vendor': [
'bootstrap/js/dropdown',
'bootstrap/js/tab',
'bootstrap/js/tooltip',
'bootstrap/js/alert',
'jquery',
'react-router',
'react-bootstrap'
],
'myapp': path.join(__dirname, 'src/stylesheets/base.scss') //'stylesheets/base.scss'
},
output: {
path: distPath,
filename: '[name].js',
libraryTarget: 'var',
library: 'exports',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js'),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'root.jQuery': 'jquery'
}),
new ExtractTextPlugin('[name].css')
],
module: {
loaders: [
{
test: /\.js$/,
loader: ['babel'],
include: path.join(__dirname, staticPrefix),
exclude: /(vendor|node_modules)/
},
{
test: /\.jsx$/,
loader: ['babel'],
include: path.join(__dirname, staticPrefix),
exclude: /(vendor|node_modules)/
},
{
test: /\.scss$/,
include: path.join(__dirname, staticPrefix),
loader: ExtractTextPlugin.extract('style-loader', 'css-loader!sass-loader-loader')
},
{
test: /\.(woff|woff2|ttf|eot|svg|png|gif|ico|jpg)($|\?)/,
loader: 'file-loader?name=' + '[name].[ext]'
}
]
},
postcss: function() {
return [autoprefixer];
},
resolve: {
modulesDirectories: [path.join(__dirname, staticPrefix), 'node_modules'],
extensions: ['', '.jsx', '.js']
},
};
The problem is that when I run: node_modules/.bin/webpack --config=webpack.config.dev it give me 2 errors:
ERROR in ./src/app.jsx
Module parse failed: /Users/work/Desktop/myapp-client/src/app.jsx Line 1: Unexpected token
You may need an appropriate loader to handle this file type.
| import React from 'react';
| console.log('hello!’);
|
# multi app
ERROR in ./src/stylesheets/base.scss
Module parse failed: /Users/work/Desktop/myapp-client/src/stylesheets/base.scss Line 1: Unexpected token {
You may need an appropriate loader to handle this file type.
| body {
| background: black;
| }
Where I'm doing wrong ?
With babel 6 you need to include the babel react preset to transpile your .jsx files. You also need to add the babel es2015 preset to transpile ES2015, i.e. ES6, syntax:
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules)/,
loader: 'babel',
query: {
presets:[ 'react', 'es2015' ]
}
}
]
}
On a side note, if you tweak your regex in the test key, you don't need two loader entries (for the .js and .jsx files).
Make sure you install these presets separately:
npm i -D babel-preset-es2015 babel-preset-react
More info on the babel 6 changes can be found here

Resources