Webpack loader fails when importing .css in react_on_rails app? - reactjs

I am trying to use react-datetime on my react-on-rails app. To make the datetime work out of the box, I need to import the CSS mentioned on their GH page.
On my app, I copy/paste the CSS into a file I named DateTime.css:
...
import DateTime from 'react-datetime';
import '../../schedules/stylesheets/DateTime.css';
...
export default class AddDate extends React.Component {
But it gives me this error:
VM45976:1 Uncaught Error: Module parse failed: /Users/some/path/to/my/project/App/components/schedules/stylesheets/DateTime.css Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
| .rdt {
| position: relative;
| }
It seems like the CSS loader is not working. I tried this on pure react app (create-react-app) and it worked. It broke when I did it inside react_on_rails.
This is my webpack config atm (standard out-of-the-box react_on_rails):
const webpack = require('webpack');
const { resolve } = require('path');
const ManifestPlugin = require('webpack-manifest-plugin');
const webpackConfigLoader = require('react-on-rails/webpackConfigLoader');
const configPath = resolve('..', 'config');
const { devBuild, manifest, webpackOutputPath, webpackPublicOutputDir } =
webpackConfigLoader(configPath);
const config = {
context: resolve(__dirname),
entry: {
'webpack-bundle': [
'es5-shim/es5-shim',
'es5-shim/es5-sham',
'babel-polyfill',
'./app/bundles/App/startup/registration',
],
},
output: {
// Name comes from the entry section.
filename: '[name]-[hash].js',
// Leading slash is necessary
publicPath: `/${webpackPublicOutputDir}`,
path: webpackOutputPath,
},
resolve: {
extensions: ['.js', '.jsx'],
},
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: 'development', // use 'development' unless process.env.NODE_ENV is defined
DEBUG: false,
}),
new ManifestPlugin({ fileName: manifest, writeToFileEmit: true }),
],
module: {
rules: [
{
test: require.resolve('react'),
use: {
loader: 'imports-loader',
options: {
shim: 'es5-shim/es5-shim',
sham: 'es5-shim/es5-sham',
},
},
},
{
test: /\.jsx?$/,
use: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: 'css-loader',
exclude: /node_modules/,
},
],
],
},
};
module.exports = config;
if (devBuild) {
console.log('Webpack dev build for Rails'); // eslint-disable-line no-console
module.exports.devtool = 'eval-source-map';
} else {
console.log('Webpack production build for Rails'); // eslint-disable-line no-console
}
I am very new in webpack, and not sure how to I can add loaders to make it work, how can I apply the DateTime.css file that I have to be applied to react-datetime?
EDIT: added css-loader (also updated the webpack above). It is no longer complaining that I don't have the correct loader, but the CSS does not work.
{
test: /\.jsx?$/,
use: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: 'css-loader',
exclude: /node_modules/,
},
],

There are 2 conceptually different ways to approach this.
1. Using CSS modules.
This way your CSS will end up bundled with your JS and as soon as webpack loads that JS module/bundle it will automatically append CSS style element into the head.
In my project I have this rule to do exactly that (note that we use both css-loader and style-loader):
{
test: /\.css$/,
use: ['style-loader', {
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]'
}
}]
}
More on css-loader modules at this link.
2. Using ExtractTextPlugin. This way all your CSS will be extracted into a separate file. The configuration requires 2 things: a plugin and loaders configuration created by the plugin:
const ExtractTextPlugin = require('extract-text-webpack-plugin');
// Add this to your webpack plugins array
new ExtractTextPlugin('styles.css')
And add this to your rules:
{
test: /\.css$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader']
})
}
This will create one single styles.css file and put all CSS you import from JS into that file.

Related

Autodesk React Forge problem with forge-dataviz-iot-react-components in a empty project

If you install the official npm package, it works.
But according to the official documentation and simply including import { Viewer } from "forge-dataviz-iot-react-components" (like in this example) in a empty new react project (using npx create-react-app) you will get this error:
./node_modules/forge-dataviz-iot-react-components/client/components/BasicTree.jsx 107:16
Module parse failed: Unexpected token (107:16)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| if (node.children.length > 0) {
| return (
> <TreeItem
| id={`tree-node-${node.id}`}
| key={node.id}
Which loader do I need to add on webpack to avoid this error?
it is not possible to include the package https://www.npmjs.com/package/forge-dataviz-iot-react-components inside a react project made with npx create-react-app (hoping Autodesk is going to fix this problem soon).
You need to edit /node_modules/react-scripts/config/webpack.config.js in 2 parts:
one line about PIXI
...
alias: {
'PIXI': "pixi.js/",
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
// Allows for better profiling with ReactDevTools
...(isEnvProductionProfile && {
'react-dom$': 'react-dom/profiling',
'scheduler/tracing': 'scheduler/tracing-profiling',
}),
...(modules.webpackAliases || {}),
},
...
and another part about /forge-dataviz-iot-react-component
...
module: {
strictExportPresence: true,
rules: [
// Disable require.ensure as it's not a standard language feature.
{ parser: { requireEnsure: false } },
{
// "oneOf" will traverse all following loaders until one will
// match the requirements. When no loader matches it will fall
// back to the "file" loader at the end of the loader list.
oneOf: [
{
test: /forge-dataviz-iot-react-component.*.jsx?$/,
use: [
{
loader: require.resolve('babel-loader'),
options: {
presets: ["#babel/react", ["#babel/env", { "targets": "defaults" }]],
plugins: ["#babel/plugin-transform-spread"]
}
},
],
exclude: path.resolve(__dirname, "node_modules", "forge-dataviz-iot-react-components", "node_modules"),
},
// TODO: Merge this config once `image/avif` is in the mime-db
// https://github.com/jshttp/mime-db
{
test: [/\.avif$/],
loader: require.resolve('url-loader'),
options: {
limit: imageInlineSizeLimit,
mimetype: 'image/avif',
name: 'static/media/[name].[hash:8].[ext]',
},
},
...
after that on /node_modules/forge-dataviz-iot-react-components/client/components/Viewer.jsx you will get errors about undefined Autodesk variable easily fixable changing Autodesk with window.Autodesk.
Although you will not see any other errors, the package will not work.
I recently tried this package and I got the same problem.
So I created a React project from scratch without CRA and followed the webpack.config.js of this repo : Forge Dataviz IOT Reference App
Here's my webpack.config.js file :
const path = require('path');
const HtmlWebPackPlugin = require('html-webpack-plugin');
module.exports = {
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
},
resolve: {
modules: [path.join(__dirname, 'src'), 'node_modules'],
alias: {
react: path.join(__dirname, 'node_modules', 'react'),
PIXI: path.resolve(__dirname, "node_modules/pixi.js/"),
},
},
devServer: {
port: process.env.PORT || 3000
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{ loader: "babel-loader" }
]
},
{
test: /forge-dataviz-iot-react-component.*.jsx?$/,
use: [
{
loader: "babel-loader",
options: {
presets: ["#babel/react", ["#babel/env", { "targets": "defaults" }]],
plugins: ["#babel/plugin-transform-spread"]
}
},
],
exclude: path.resolve(__dirname, "node_modules", "forge-dataviz-iot-react-components", "node_modules"),
},
{
test: /\.css$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
},
],
},
{
test: /\.svg$/i,
use: {
loader: "svg-url-loader",
options: {
// make loader to behave like url-loader, for all svg files
encoding: "base64",
},
},
},
],
},
plugins: [
new HtmlWebPackPlugin({
template: './src/index.html',
}),
],
};
Update :
If you want to use CRA, you can customise your webpack config using Customize-CRA and create a config-overrides.js like this :
/* config-overrides.js */
const path = require("path");
const {
override,
addExternalBabelPlugins,
babelInclude,
babelExclude,
addWebpackAlias
} = require("customize-cra");
module.exports = override(
babelInclude([
path.resolve("src"), // make sure you link your own source
path.resolve("node_modules")
]),
babelExclude([path.resolve("node_modules/forge-dataviz-iot-react-components/node_modules")]),
addWebpackAlias({
['PIXI']: path.resolve(__dirname, 'node_modules/pixi.js/')
})
);
I managed to make this work on a fresh CreateReactApp project, so you should be able to make it working on your project.

Error while importing font or images file inside scss using Webpack 4 and react js

I am using webpack and react js.
I am getting this error when i try to import image or font file inside my scss file.
I have tried many solutions but none of them solved my problem,
webpack.common.js
enter image description here
const path = require("path");
var HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: {
main: "./src/index.js",
vendor: "./src/vendor.js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: ["html-loader"]
},
{
test: /\.(ttf|svg|png|jpg|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[hash].[ext]",
outputPath: "imgs"
}
}
}
]
}
};
Here is another webpack.dev.js
module.exports = merge(common, {
mode: "development",
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "dist")
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/template.html"
})
],
module: {
rules: [
{
test: /\.scss$/,
use: [
"style-loader", //3. Inject styles into DOM
"css-loader", //2. Turns css into commonjs
"sass-loader" //1. Turns sass into css
]
}
]
}
});
ERROR in ./src/assets/index.scss (./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/lib/loader.js!./src/assets/index.scss)
Module not found: Error: Can't resolve '../../../src/assets/fonts/icomoon.ttf' in 'C:\Users\jamal\Documents\webpack-demo-app\src\assets'
# ./src/index.js
# multi (webpack)-dev-server/client?http://localhost:8080 ./src/index.js
You need to remember that the import actually takes "place" from the root index.scss file (the one that loads all the other partials). So the path you are using to fetch the asset is not accurate.
You need to use ./fonts/icomoon.ttf instead of ../fonts/icomoon.ttf
your file structure:
assets/
------/fonts
------/images
------/sass
------/---/partial1.scss // while the reference to the image is here
------/index.scss // the actual root of the reference call is here

React Module parse failed: Unexpected character '#'

I am getting an error when trying to import the following in my react component:
import FontIconPicker from '#fonticonpicker/react-fonticonpicker';
import '#fonticonpicker/react-fonticonpicker/dist/fonticonpicker.base-theme.react.css';
I'm using this module: https://fonticonpicker.github.io/react-fonticonpicker/
I get this error:
./node_modules/#fonticonpicker/react-fonticonpicker/dist/fonticonpicker.base-theme.react.css
Module parse failed: Unexpected character '#' (18:0) You may need an
appropriate loader to handle this file type. | * | / |
#font-face{font-family:fontIconPicker;src:url(assets/fontIconPicker.ttf)
format("truetype"),url(assets/fontIconPicker.woff)
format("woff"),url(assets/fontIconPicker.svg#fontIconPicker)
format("svg");font-weight:400;font-style:normal}[class="
fipicon-"],[class^=fipicon-]{font-family:fontIconPicker!important;speak:none;font-style .......
The error can be reproduced with my code from github: https://github.com/gregbia/my-app
Use npm install, and npm start and the error will show.
My webpack looks like this:
/**
* Webpack Configuration
*
* Working of a Webpack can be very simple or complex. This is an intenally simple
* build configuration.
*
* Webpack basics — If you are new the Webpack here's all you need to know:
* 1. Webpack is a module bundler. It bundles different JS modules together.
* 2. It needs and entry point and an ouput to process file(s) and bundle them.
* 3. By default it only understands common JavaScript but you can make it
* understand other formats by way of adding a Webpack loader.
* 4. In the file below you will find an entry point, an ouput, and a babel-loader
* that tests all .js files excluding the ones in node_modules to process the
* ESNext and make it compatible with older browsers i.e. it converts the
* ESNext (new standards of JavaScript) into old JavaScript through a loader
* by Babel.
*
* TODO: Instructions.
*
* #since 1.0.0
*/
const paths = require( './paths' );
const autoprefixer = require( 'autoprefixer' );
const ExtractTextPlugin = require( 'extract-text-webpack-plugin' );
// Extract style.css for both editor and frontend styles.
const blocksCSSPlugin = new ExtractTextPlugin( {
filename: './dist/blocks.style.build.css',
} );
// Extract editor.css for editor styles.
const editBlocksCSSPlugin = new ExtractTextPlugin( {
filename: './dist/blocks.editor.build.css',
} );
// Configuration for the ExtractTextPlugin — DRY rule.
const extractConfig = {
use: [
// "postcss" loader applies autoprefixer to our CSS.
{ loader: 'raw-loader' },
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
autoprefixer( {
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
} ),
],
},
},
// "sass" loader converts SCSS to CSS.
{
loader: 'sass-loader',
options: {
// Add common CSS file for variables and mixins.
data: '#import "./src/common.scss";\n',
outputStyle: 'nested',
},
},
],
};
// Export configuration.
module.exports = {
entry: {
'./dist/blocks.build': paths.pluginBlocksJs, // 'name' : 'path/file.ext'.
},
output: {
// Add /* filename */ comments to generated require()s in the output.
pathinfo: true,
// The dist folder.
path: paths.pluginDist,
filename: '[name].js', // [name] = './dist/blocks.build' as defined above.
},
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
devtool: 'cheap-eval-source-map',
module: {
rules: [
{
test: /\.(js|jsx|mjs)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
// #remove-on-eject-begin
babelrc: false,
presets: [ require.resolve( 'babel-preset-cgb' ) ],
// #remove-on-eject-end
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
},
},
},
{
test: /style\.s?css$/,
exclude: /(node_modules|bower_components)/,
use: blocksCSSPlugin.extract( extractConfig ),
},
{
test: /editor\.s?css$/,
exclude: /(node_modules|bower_components)/,
use: editBlocksCSSPlugin.extract( extractConfig ),
},
],
},
// Add plugins.
plugins: [ blocksCSSPlugin, editBlocksCSSPlugin ],
stats: 'minimal',
// stats: 'errors-only',
// Add externals.
externals: {
react: 'React',
'react-dom': 'ReactDOM',
ga: 'ga', // Old Google Analytics.
gtag: 'gtag', // New Google Analytics.
jquery: 'jQuery', // import $ from 'jquery' // Use the WordPress version.
},
};
Actually, I'm so surprised that you used SCSS webpack configs beside the PostCSS because with a little configuration you can pre-process your CSSes and then post-process them to a compressed version by SCSS syntax. I set a config you in this link. I know it is not your main problem but I think your project configuration is not optimized.
The above link of webpack config will help you to make your configuration better and you can see the webpack configs of fonts. any way...
For your exact error, you should fix your font configuration on webpack just like below:
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
exclude: /node_modules/,
loader: 'file-loader',
options: {
limit: 1024,
name: '[name].[ext]',
publicPath: 'dist/assets/',
outputPath: 'dist/assets/'
}
},
Update after work on the repo:
I write the webpack.config.dev.js file like below:
const paths = require('./paths');
const externals = require('./externals');
const autoprefixer = require('autoprefixer');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
// Extract style.css for both editor and frontend styles.
const blocksCSSPlugin = new ExtractTextPlugin({
filename: './dist/blocks.style.build.css',
});
// Extract editor.css for editor styles.
const editBlocksCSSPlugin = new ExtractTextPlugin({
filename: './dist/blocks.editor.build.css',
});
// Configuration for the ExtractTextPlugin — DRY rule.
const extractConfig = {
fallback: 'style-loader',
use: [
// "postcss" loader applies autoprefixer to our CSS.
{loader: 'css-loader'},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
// "sass" loader converts SCSS to CSS.
{
loader: 'sass-loader',
options: {
// Add common CSS file for variables and mixins.
data: '#import "./src/common.scss";\n',
outputStyle: 'nested',
},
},
],
};
// Export configuration.
module.exports = {
entry: {
'./dist/blocks.build': paths.pluginBlocksJs, // 'name' : 'path/file.ext'.
},
output: {
// Add /* filename */ comments to generated require()s in the output.
pathinfo: true,
// The dist folder.
path: paths.pluginDist,
filename: '[name].js', // [name] = './dist/blocks.build' as defined above.
},
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
devtool: 'cheap-eval-source-map',
module: {
rules: [
{
test: /\.(js|jsx|mjs)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
// #remove-on-eject-begin
babelrc: false,
presets: [require.resolve('babel-preset-cgb')],
// #remove-on-eject-end
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
},
},
},
{
test: /style\.s?css$/,
exclude: /(node_modules|bower_components)/,
use: blocksCSSPlugin.extract(extractConfig),
},
{
test: /editor\.s?css$/,
exclude: /(node_modules|bower_components)/,
use: editBlocksCSSPlugin.extract(extractConfig),
},
{
test: /\.css$/,
include: /(node_modules\/#fonticonpicker\/react-fonticonpicker\/dist)/,
loaders: ['style-loader', 'css-loader']
},
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
include: /(node_modules\/#fonticonpicker\/react-fonticonpicker\/dist)/,
loader: 'file-loader',
options: {
limit: 1024,
name: '[name].[ext]',
publicPath: 'dist/assets/',
outputPath: 'dist/assets/'
}
}
],
},
// Add plugins.
plugins: [blocksCSSPlugin, editBlocksCSSPlugin],
stats: 'minimal',
// stats: 'errors-only',
// Add externals.
externals: externals,
};
And also install css-loader and file-loader.
npm install file-loader css-loader
Hint: it seems fonts need to have an outputPath in webpack configuration.
The problem is webpack is not loading your fonts #font-face in node_modules. You are excluding the loading of css from node_modules. But your #fonticonpicker/react-fonticonpicker/dist/fonticonpicker.base-theme.react.css is in node_modules.
Change this snippet in your webpack config
{
test: /style\.s?css$/,
exclude: /(node_modules|bower_components)/,
use: blocksCSSPlugin.extract( extractConfig ),
},
{
test: /editor\.s?css$/,
exclude: /(node_modules|bower_components)/,
use: editBlocksCSSPlugin.extract( extractConfig ),
},
to
{
test: /style\.s?css$/,
use: blocksCSSPlugin.extract( extractConfig ),
},
{
test: /editor\.s?css$/,
use: editBlocksCSSPlugin.extract( extractConfig ),
},
{ test: /(\.css$)/, // you need to load all css imported from node_modules
loaders: ['style-loader', 'css-loader', 'postcss-loader']
}
Seems like you're missing css-loader for .css stored in node_modules. That is why you are facing this issue. Run npm i -D css-loader and add this rule to your node_modules > cgb-scrips > config > webpack.config.<env>.js file:
module: {
rules: [
// ...
{
test: /\.css$/,
use: [
{ loader: 'raw-loader' },
{ loader: 'css-loader' },
]
},
// ...
],
},
Alternatively, to skip editing webpack.config.js you could simply import your files like so:
import 'raw-loader!css-loader!#fonticonpicker/react-fonticonpicker/dist/fonticonpicker.base-theme.react.css';
import 'raw-loader!css-loader!#fonticonpicker/react-fonticonpicker/dist/fonticonpicker.material-theme.react.css';
Your loader config in webpack doesn't match the CSS file Route.
import '#fonticonpicker/react-fonticonpicker/dist/fonticonpicker.base-theme.react.css';
It is neither style.css or editor.css. Hence you get an error. Also you are ignoring node_modules in your webpack loader config but you import the css from node_modules.
Adding
{
test: /react\.s?css$/,
use: [{
loader: 'css-loader',
options: {
modules: true
}
}],
},
should work

Storybook doesn't understand import on demand for antd components

I have followed instructions here to get antd working fine with CRA. But while using it from storybook, I was getting an error as:
Build fails against a mixin with message Inline JavaScript is not
enabled. Is it set in your options?
I had fixed that following suggestions on an issue I raised here.
Now, storybook understands antd but not importing components on demand. Is babel has to be configured separately for storybook?
1. On using import { Button } from "antd";
I get this:
2. On using
import Button from "antd/lib/button";
import "antd/lib/button/style";
I get:
Storybook version: "#storybook/react": "^3.4.8"
Dependency: "antd": "^3.7.3"
I have been stuck (again) with this for quite long hours googling things, any help is appreciated. Thanks!
Using Storybook 4, you can create a webpack.config.js file in the .storybook directory with the following configuration:
const path = require("path");
module.exports = {
module: {
rules: [
{
loader: 'babel-loader',
exclude: /node_modules/,
test: /\.js$/,
options: {
presets: ["#babel/react"],
plugins: [
['import', {libraryName: "antd", style: true}]
]
},
},
{
test: /\.less$/,
loaders: [
"style-loader",
"css-loader",
{
loader: "less-loader",
options: {
modifyVars: {"#primary-color": "#d8df19"},
javascriptEnabled: true
}
}
],
include: path.resolve(__dirname, "../")
}
]
}
};
Note that the above snippet includes a style overwriting of the primary button color in antd. I figured, you might want to eventually edit the default theme so you can remove that line in case you do not intend to do so.
You can now import the Button component in Storybook using:
import {Button} from "antd";
without having to also import the style file.
If you are using AntD Advanced-Guides for React and storybook v5 create .storybook/webpack.config.js with the following:
const path = require('path');
module.exports = async ({ config, mode }) => {
config.module.rules.push({
loader: 'babel-loader',
exclude: /node_modules/,
test: /\.(js|jsx)$/,
options: {
presets: ['#babel/react'],
plugins: [
['import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true
}]
]
},
});
config.module.rules.push({
test: /\.less$/,
loaders: [
'style-loader',
'css-loader',
{
loader: 'less-loader',
options: {
modifyVars: {'#primary-color': '#f00'},
javascriptEnabled: true
}
}
],
include: [
path.resolve(__dirname, '../src'),
/[\\/]node_modules[\\/].*antd/
]
});
return config;
};
Then you can use import { Button } from 'antd' to import antd components.
I'm currently using storybook with antd and i got it to play nice, by using this config in my webpack.config.js file in the .storybook folder:
const { injectBabelPlugin } = require('react-app-rewired');
const path = require("path");
module.exports = function override(config, env) {
config = injectBabelPlugin(
['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }],
config,
);
config.module.rules.push({
test: /\.css$/,
loaders: ["style-loader", "css-loader", ],
include: path.resolve(__dirname, "../")
})
return config;
};

How can I set a CSS name not to be a hash in a Webpack configuration file?

I just wondering why my CSS name became hash after I build and run my React + Webpack application. Is there advance configuration that I may have missed to set the CSS name as normal?
This is my Webpack configuration:
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: './app/app.jsx',
output: {
path: __dirname,
filename: './public/bundle.js'
},
resolve: {
alias: {
applicationStyles: path.resolve(__dirname,'app/styles/app.css'),
Clock: path.resolve(__dirname,'app/components/Clock.jsx'),
Countdown: path.resolve(__dirname,'app/components/Countdown.jsx'),
CountdownForm: path.resolve(__dirname,'app/components/CountdownForm.jsx')
},
extensions: ['.js', '.jsx']
},
module: {
rules: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
]
},
devtool: 'cheap-module-eval-source-map'
};
This is the CSS name that becomes hash:
To be more clear, I add the source code of how I import and use the CSS on React:
import React from 'react';
import ReactDOM from 'react-dom';
import Countdown from 'Countdown';
/* Import the CSS file */
import Styles from 'applicationStyles';
ReactDOM.render(
/* Use CSS */
<div className={Styles.box}>
<Countdown/>
</div>,
document.getElementById('app')
);
This is what Webpack does by default to avoid identical CSS classes (from different CSS modules) to collide.
Here are three things you can do:
1: At the app level, you can add the following configuration to your Webpack to disable CSS modules. It is not recommended as it could lead to collisions and hard-to-find bugs.
options: {
modules: false
}
2: At the file level, you can import it like this to prevent Webpack from obfuscating the class names. This is useful when importing third-party configuration libraries CSS files.
import '!style!css!golden-layout-css-base';
3: At the CSS class level, you can use :global(.your-class-name) to avoid obfuscating a specific class
:global(.container) {
padding: 10px;
}
In your Webpack configuration, the CSS loader needs a configuration for prefixed names. Basically localIdentName:'[local]' sets the pre-fixer as the local class name only.
For detailed info, you can look at the documentation for CSS Loader
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true,
localIdentName:'[local]'
}
}
]
}
]
}
The class name can be combined with an auto-generated hash using the localIdentName option of CSS Modules by setting it to [local]_[hase:base64:5].
[local] here refers to the class name.
[hash:base64:5] means generate a Base64 hash string of length 5.
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[local]_[hash:base64:5]'
}
}
]
}
By setting the css-loader modules options to an object, you're essentially setting modules to true, but with specific options.
Setting the localIdentName to [local] completely defeats the purpose of using CSS Modules.

Resources