React Module parse failed: Unexpected character '#' - reactjs

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

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.

Module parse failed: Unexpected character '#' (1:0) with Storybook 6.1.11, Webpack 5.11.0, React 17.0.1

Trying to setup a react-app with all latest versions.
Github Repo Link
Trying to run storybook with sass file imported will result in below error. Trying to run without importing the styles, storybook works.
The same code works correctly when its run as npm start run with no warnings and errors.
I have configured css modules using #dr.pogodin/babel-plugin-react-css-modules with sass, webpack 5, react 17 and with latest packages.
ERROR in ./src/assets/stylesheets/app.scss 1:0
Module parse failed: Unexpected character '#' (1:0)
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
> #import "./base.scss";
| #import "./generics/font.scss";
| #import "./generics/spacing.scss";
# ./stories/index.js 5:0-44 8:2-10:4 8:58-10:3 9:4-49
# ./src/components/atoms/button/stories.js
babel.config.js
module.exports = {
presets: ["#babel/preset-env", "#babel/preset-react"],
plugins: [
[
"#dr.pogodin/babel-plugin-react-css-modules",
{
webpackHotModuleReloading: true,
autoResolveMultipleImports: true,
filetypes: {
".scss": {
syntax: "postcss-scss",
},
},
generateScopedName: "[name]__[local]___[hash:base64:5]",
},
],
],
};
webpack.config.js for css (partial code inlcuded)
{
test: /\.(css|sass|scss)$/,
exclude: /node_modules/,
use: [
isDev ? "style-loader" : MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: {
auto: (resourcePath) =>
resourcePath.indexOf("assets/stylesheets") === -1,
localIdentName:"[name]__[local]___[hash:base64:5]",
},
sourceMap: true,
},
},
"sass-loader",
],
}
storybook/webpack.config.js file
const custom = require('../webpack.config.js');
module.exports = {
// stories: ['../src/components/**/*.stories.js'],
webpackFinal: (config) => {
return {
...config,
module: {
rules: custom.module.rules,
},
resolve: {
...config.resolve,
...custom.resolve,
}
};
},
};
I don't know what you have done with your configuration but you would define the config things inside .storybook/main.js. And for global style css is supposed to be included in preview.js file.
In short, you have to do the few things:
Remove your .storybook/config.js and add .storybook/main.js with following content:
const custom = require('../webpack.config.js');
module.exports = {
stories: [
'../src/**/stories.js', // The name should have a prefix for component name like `button.stories.js` instead of `stories.js` like you've done. As you renamed, you can remove this pattern
"../src/**/*.stories.#(js|jsx|ts|tsx)"
],
webpackFinal: (config) => {
return {
...config,
module: {
rules: custom.module.rules,
},
resolve: {
...config.resolve,
...custom.resolve,
}
};
},
};
Create the .storybook/preview.js to import your global style:
import "../src/assets/stylesheets/app.scss";
Some people have been running into problems a some scss preset when using Storybook 6.2.0 with Webpack 5. Instead of using a preset, I recommend configuring the Webpack config in main.js as mentioned above. Here's the relevant portion of a working Storybook Webpack config for Sass:
module: {
...config.module,
rules: [
...config.module.rules,
{
test: /\.(scss)$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: function () {
return [require('precss'), require('autoprefixer')];
},
},
},
},
{
loader: require.resolve('sass-loader'),
options: {
implementation: require('sass'),
},
},
],
},
],
},
I've written more about getting Storybook off the ground with Webpack 5 (and modifying the Storybook Webpack config) over here.
Another reason this might happen: if you are adding new components to your app and the path defined for your sass-loader does not match anymore.
E.g. if you have this in your .storybook/main.js:
webpackFinal: async config => {
// Add SASS support
// https://storybook.js.org/docs/configurations/custom-webpack-config/#examples
config.module.rules.push({
test: /\.scss$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: {
compileType: "icss",
},
},
},
"sass-loader",
],
include: path.resolve(__dirname, "../"),
})
Update or completely remove the include path.

Isolate specific config files from main bundle

I have a couple of config files in my application that a want in a separate bundle or not bundled at all but copied to the output folder and read by the main bundle somehow.
I've managed to get my files into a separate config bundle, but the problem is that these files are also still bundled into the main bundle, in effect rendering my config bundle useless.
I've managed to get the config bundle working with the help of #Chase, but I'm not happy yet. Next I want to know how to have these files not bundled at all, but still available to the main bundle after deployment.
ANY SUGGESTIONS?
My project folder/file structure (the essential bits):
- app
- js
- components
- [all of my components]
- config
- [my config files that I want to isolate]
- App.jsx
- index.jsx
- ...
- ...
My webpack config:
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const cwd = process.cwd()
const mode = 'production'
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
context: path.join(cwd, 'app'),
mode,
optimization: {
runtimeChunk: 'single',
minimize: false,
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 0,
cacheGroups: {
config: {
test: /[\\/]app[\\/]js[\\/]config[\\/]/,
minSize: 0
},
vendors: {
test: /[\\/]node_modules[\\/]/,
name(module) {
// get the name. E.g. node_modules/packageName/not/this/part.js
// or node_modules/packageName
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
// npm package names are URL-safe, but some servers don't like # symbols
return `npm.${packageName.replace('#', '')}`;
},
}
},
},
},
entry: {
app: ["babel-polyfill", './js/index.jsx'],
silentRenew: ["./silent_renew/silent_renew.js"],
},
output: {
path: path.resolve('dist'),
filename: 'bundle_[name].js'
},
module: {
rules: [{
test: /\.jsx?$/,
use: ['babel-loader'],
exclude: /node_modules/
},
{
test: /\.json$/,
use: ['json-loader'],
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'scss-loader'
]
},
{
test: /\.(png|jpg|jpeg|svg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
},
{
test: /\.(pptx|zip)$/,
loader: "file-loader",
options: {
name: '[name].[ext]'
}
}]
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
template: './index.ejs',
excludeChunks: ["silentRenew"],
}),
new HtmlWebpackPlugin({
template: "./silent_renew/silent_renew.html",
chunks: ["silentRenew",],
filename: "silent_renew.html"
}),
new webpack.DefinePlugin({
CONSTANTS: {
PROD: false,
TEST: true,
DEV: false
}
}),
new webpack.IgnorePlugin(/^(fs|ipc|ignore)$/)
]
}
I want my config files to go into the config bundle, this is already working.
But then I also need them to not be included in the main bundle.
Even better would be if I could have the config files not bundled at all and just copied to the output folder and read from there by the main (app) bundle. But an isolated config bundle is second option.
You need to chunk out your bundle based on conditions. This is an example of splitting out node_modules into a "common" bundle, but you can rewrite the test property to match your directory conditions.
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "common",
chunks: "all"
}
}
}

Webpack loader fails when importing .css in react_on_rails app?

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.

SCSS files not importing in create-react-app

I'm using the React cli create-react-app and trying to load in a .scss file from a UI library http://react-conventions.herokuapp.com/. I've already run npm run eject and added the following to loaders in the config.dev I also downloaded the sass-loader already.
var path = require('path');
var autoprefixer = require('autoprefixer');
var webpack = require('webpack');
var findCacheDir = require('find-cache-dir');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
var WatchMissingNodeModulesPlugin = require('react-dev- utils/WatchMissingNodeModulesPlugin');
var getClientEnvironment = require('./env');
var paths = require('./paths');
var publicPath = '/';
var env = getClientEnvironment(publicUrl);
module.exports = {
entry: [
require.resolve('react-dev-utils/webpackHotDevClient'),
require.resolve('./polyfills'),
paths.appIndexJs
],
output: {
path: paths.appBuild,
pathinfo: true,
filename: 'static/js/bundle.js',
publicPath: publicPath
},
resolve: {
fallback: paths.nodePaths,
extensions: ['.js', '.json', '.jsx', ''],
alias: {
'react-native': 'react-native-web'
}
},
module: {
// First, run the linter.
// It's important to do this before Babel processes the JS.
preLoaders: [
{
test: /\.(js|jsx)$/,
loader: 'eslint',
include: paths.appSrc,
}
],
loaders: [
// Process JS with Babel.
{
test: /\.(js|jsx)$/,
include: paths.appSrc,
loader: 'babel',
query: {
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/react-scripts/
// directory for faster rebuilds. We use findCacheDir() because of:
// https://github.com/facebookincubator/create-react-app/issues/483
cacheDirectory: findCacheDir({
name: 'react-scripts'
})
}
},
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader turns CSS into JS modules that inject <style> tags.
// In production, we use a plugin to extract that CSS to a file, but
// in development "style" loader enables hot editing of CSS.
{
test: /\.css$/,
loader: 'style!css?importLoaders=1!postcss'
},
{
test: /\.scss$/,
loaders: ["style", "css", "sass"],
exclude: /node_modules(?!\/react-conventions)/
},
{
test: /\.sass$/,
loaders: ["style", "css", "sass"]
},
// JSON is not enabled by default in Webpack but both Node and Browserify
// allow it implicitly so we also enable it.
{
test: /\.json$/,
loader: 'json'
},
// "file" loader makes sure those assets get served by WebpackDevServer.
// When you `import` an asset, you get its (virtual) filename.
// In production, they would get copied to the `build` folder.
{
test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
loader: 'file',
query: {
name: 'static/media/[name].[hash:8].[ext]'
}
},
// "url" loader works just like "file" loader but it also embeds
// assets smaller than specified size as data URLs to avoid requests.
{
test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/,
loader: 'url',
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
}
]
},
// We use PostCSS for autoprefixing only.
postcss: function() {
return [
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
]
}),
];
},
plugins: [
new InterpolateHtmlPlugin({
PUBLIC_URL: publicUrl
}),
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
}),
new webpack.DefinePlugin(env),
// This is necessary to emit hot updates (currently CSS only):
new webpack.HotModuleReplacementPlugin(),
new CaseSensitivePathsPlugin(),
new WatchMissingNodeModulesPlugin(paths.appNodeModules)
],
node: {
fs: 'empty',
net: 'empty',
tls: 'empty'
}
};
I try to import in my component using import Input from 'react-conventions/lib/Input'; But I'm still getting an error
Failed to compile.
Error in ./~/react-conventions/lib/components/Input/style.scss
Module parse failed: /Users/user/Desktop/App/node_modules/react- conventions/lib/components/Input/style.scss Unexpected character '#' (1:0)
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected character '#' (1:0)
# ./~/react-conventions/lib/components/Input/Input.js 19:13-36
Could this be a problem with the library? Doubtful but I'm just not seeing what I'm missing.
try this (exclude with a negative lookahead):
{
test: /\.scss$/,
loaders: ["style", "css", "sass"],
exclude: /node_modules(?!\/react-conventions)/
}
Try adding this to your package.json scripts
"scripts": {
"build-css": "node-sass src/ -o src/",
"watch-css": "npm run build-css && node-sass src/ -o src/ --watch --recursive"
and install also node-sass since the scripts depend on it.
This will work assuming you haven't eject your project yet.

Resources