add scss (bootstrap) compilation with output css file in react project - reactjs

I have a react/express project
I want to be able to customize the Bootstrap 4 and output a CSS file which will contain the customized boostrap.css.
I have npm installed the loaders bootstrap needs ( postcss-loader,sass-loader,style-loader etc), although in web I saw an example with ExtractTextPlugin in order to get output file
when I run the webpack config I get an error
" throw new Error("'output.filename' is required, either in config file or as --output-filename");"
Any tutorial/help how to accomplish compiling customized bootstrap in seperate output file?
webpack config
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
//root file for the client/browser app
entry: './src/client/client.js',
//output file and its location
output: {
filename: 'bundle.js',
path: path.resolve(__dirname,'public'),
},
//run babel for every filename
module: {
rules: [
{
test: /\.js?$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets:
[
'react',
'stage-0',
[
'env',
{
targets:
{
browsers:
['last 2 versions']
}
}
]
]
}
}
]
},
};
module.exports = {
// root file for the client/browser app
entry: './src/client/styles/main.scss',
// output file and its location
output: {
filename: 'styles2.css',
path: path.resolve(__dirname,'public'),
},
module: {
loaders: [
// ...
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('css!sass')
}
]
},
plugins: [
new ExtractTextPlugin('public/style.css', {
allChunks: true,
})
]
};

You need to remove the extra module.exports. I do not see the need to have two of these as you can simply achieve the same thing inside a single module.exports.
You can achieve this like so:
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
//root file for the client/browser app
entry: [
'./src/client/client.js',
'./src/client/styles/main.scss'
],
//output file and its location
output: {
filename: 'bundle.js',
path: path.resolve(__dirname,'public'),
},
//run babel for every filename
module: {
rules: [
{
test: /\.js?$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets:[
'react',
'stage-0',
[
'env',
{
targets:
{
browsers:
['last 2 versions']
}
}
]
]
}
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('css-loader!sass-loader')
}
],
plugins: [
new ExtractTextPlugin('public/style.css', {
allChunks: true,
})
]
},};

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.

webpack Can't resolve '../../assets/icon-font/icomoon.eot?e3uwku' in 'D:\sudi\aa-Server-side-render\MAPS101_Fresh_ssr\src\scss'

I want to implement SSR in an already build react application.
I am trying to include icon-fonts and ignore CSS files from node_modules of a particular library
Please help me, I am stuck here!!
I'm trying to load a font in my SCSS file but giving the below error.
my folder structure is :
my webpack.config.js is:
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
// webpack optimization mode
mode: ('development' === process.env.NODE_ENV ? 'development' : 'production'),
// entry files
entry: 'development' === process.env.NODE_ENV ? [
'./src/index.js', // in development
] : [
'./src/index.js', // in production
],
// output files and chunks
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'build/[name].js',
},
// module/loaders configuration
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react']
}
},
exclude: [/node_modules/, /static/]
},
{
test: /\.(sa|sc|c)ss$/,
use: [
true ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
],
exclude: [/node_modules/, /static/]
},
{
test: /\.(css)$/,
use: [{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '/public/css'
}
}, 'css-loader'],
exclude: [/node_modules/, /static/]
},
{
test: /\.(jpg|jpeg|png|svg|gif)$/,
use: [{
loader: 'file-loader',
options: {
name: '[md5:hash:hex].[ext]',
publicPath: '/public/img',
outputPath: 'img'
}
}]
},
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/font-woff',
},
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/font-woff',
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/octet-stream',
},
{
test: /\.otf(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/octet-stream',
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: 'url-loader?limit=10000&mimetype=application/vnd.ms-fontobject',
},
]
},
// webpack plugins
plugins: [
// extract css to external stylesheet file
new MiniCssExtractPlugin({
filename: 'build/styles.css'
}),
// prepare HTML file with assets
new HTMLWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, 'src/index.html'),
minify: false,
}),
// copy static files from `src` to `dist`
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, 'src/assets'),
to: path.resolve(__dirname, 'dist/assets')
}
]
}),
],
// resolve files configuration
resolve: {
// file extensions
extensions: ['.js', '.jsx', '.css', '.scss'],
},
// webpack optimizations
optimization: {
splitChunks: {
cacheGroups: {
default: false,
vendors: false,
vendor: {
chunks: 'all', // both : consider sync + async chunks for evaluation
name: 'vendor', // name of chunk file
test: /node_modules/, // test regular expression
}
}
}
},
// development server configuration
devServer: {
port: 8088,
historyApiFallback: true,
}, // generate source map
devtool: 'source-map' };
For me, I had the icomoon font in fonts directory. Did some investigation and found that the .scss file was trying to link it like this
url("./assets/styles/fonts/icomoon.svg?y2smka#icomoon"). The problem with that is icomoon.svg?y2smka#icomoon does not exist. So I looked in the fonts directory and found that it's called icomoon.eot
Solution:
In your _fonts.scss file, change all url("./assets/styles/fonts/icomoon.svg?y2smka#icomoon"). to url("./icomoon.eot")

Webpack running through grunt webpack doesn't error or complete, or do anything

Trying to convert an old system off bower into npm using webpack, and grunt webpack. Just trying to use webpack to load in NPM files, not run anything else, and the rest of the grunt file finishes loading and uglifying and stuff, and runs its own node server. It gets to this point and freezes and never comes back.
Loading "grunt-webpack" plugin
Registering "/Users/***/***/***/node_modules/grunt-webpack/tasks" tasks.
Loading "webpack-dev-server.js" tasks...OK
+ webpack-dev-server
Loading "webpack.js" tasks...OK
+ webpack
Running "webpack" task
Here's my grunt code (super basic obviously)
webpack: {
options: require("./config/webpack.dev.js"),
},
Here's that dev file
const webpack = require('webpack');
const helpers = require('./helpers');
const merge = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { BaseHrefWebpackPlugin } = require('base-href-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ConcatPlugin = require('webpack-concat-plugin');
const ngInventory = require('./ng1-vendor-index.js');
const common = require('./webpack.common.js');
const ENV = process.env.NODE_ENV = process.env.ENV = 'dev';
module.exports = merge(common(ENV), {
devtool: 'source-map',
module: {
rules: [
{
test: /\.(ts|js)$/,
loaders: ['angular-router-loader'],
},
{
test: /\.((s*)css)$/,
use: [{
loader: 'style-loader',
},{
loader: 'css-loader',
},{
loader: 'sass-loader',
}]
},
{
test: /src\/.+\.(ts|js)$/,
exclude: /(node_modules|\.spec\.ts$)/,
loader: 'istanbul-instrumenter-loader',
enforce: 'post',
options: {
esModules: true
}
}
]
},
debug: true,
devTool: 'eval',
plugins: [
new ConcatPlugin({
uglify: false,
sourceMap: true,
name: 'vendor',
outputPath: './',
fileName: '[name].[hash].js',
filesToConcat: ngInventory.vendor1
}),
new BaseHrefWebpackPlugin({ baseHref: '/'}),
new HtmlWebpackPlugin({
favicon: helpers.root('client/assets/image/favicon.png'),
template: "./client/index.html",
filename: "./client/index.html",
}),
new webpack.NoEmitOnErrorsPlugin(),
],
});
And here is the common file:
const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals')
const helpers = require('./helpers');
module.exports = env => ({
entry: {
server: './server/app.js',
},
resolve: {
extensions: ['.ts', '.js']
},
output: {
path: helpers.root(`dist/${env}`),
publicPath: '/',
filename: '[name].js'
},
target: 'node',
node: {
// Need this when working with express, otherwise the build fails
__dirname: false, // if you don't put this is, __dirname
__filename: false, // and __filename return blank or /
},
externals: [nodeExternals()],
module: {
rules: [
{
// Transpiles ES6-8 into ES5
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
include: [
helpers.root('client'),
],
loader: 'html-loader'
},
{
test: /\.((s*)css)%/,
include: [
helpers.root('client/app'),
helpers.root('client/components'),
],
exclude: 'node_modules/',
loaders: ['to-string-loader', 'css-loader', 'sass-loader']
},
{
test: /\.(woff|woff2|eot|tts)$/,
use: [{
loader: 'file-loader'
}]
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
'ENV': JSON.stringify(env)
}
}),
new webpack.ContextReplacementPlugin(/\#angular(\\|\/)core(\\|\/)esm5/, path.join(__dirname, './client')),
]
});
A sample from the vendor index file:
const helper = require('./helpers');
exports.vendor1 = [
helper.root('node_modules/lodash/lodash.js'),
helper.root('node_modules/lodash-deep/lodash-deep.js'),
...
...
]
I'm just really not sure what to do, couldn't bring up any google results or stack results because theres no errors happening either. I've tried all verbose levels of logging all to no avail. What in the world am I missing?
As the documentation shows, you haven't configured any targets, like dev or prod. You've only specified options. You want
webpack: {
options: {},
dev: require("./config/webpack.dev.js"),
},
As an aside, there's no benefit to using Webpack with Grunt.

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 4 configuration for react-toolbox

I try to upgrade my app from webpack 2 to webpack 4.16.5.
Because I want not again end up in a hard to understand some hundreds line config, I start with a minimal config. This is my current:
const path = require("path");
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const context = path.resolve(__dirname, "app");
module.exports = {
entry: {
home: "./index.js"
},
context,
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
},
{
test: /\.(css|sass|scss)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader"
},
{
loader: "postcss-loader"
},
{
loader: "sass-loader"
}
]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./index.html",
filename: "./index.html"
}),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
],
resolve: {
extensions: [".js", ".jsx", ".css", "json"],
modules: [path.resolve(__dirname, "node_modules"), context]
}
};
But I run in problems importing the CSS files from react-toolbox i.e.:
import Dialog from 'react-toolbox/lib/dialog';
in a js file and also
#import "react-toolbox/lib/button/theme.css";
causes errors like this:
ERROR in ../node_modules/react-toolbox/lib/switch/theme.css (../node_modules/css-loader!../node_modules/postcss-loader/src!../node_modules/sass-loader/lib/loader.js!../node_modules/react-toolbox/lib/switch/theme.css)
Module build failed (from ../node_modules/css-loader/index.js):
Error: composition is only allowed when the selector is single: local class name not in ".disabled", ".disabled" is weird
Does anyone have a working application with wbpack4 and react-toolbox? Also, any hints on what may cause these errors are welcome!
I'm learning react.js with the js stack from scratch tutorial and try to using react-toolbox components.
Finnaly, i have a working demo with webpack 4 and the react-toolbox, it's based on the react-toolbox-example.
This is my settings:
add css-modules related packages
$ npm install postcss postcss-cssnext postcss-import postcss-loader css-loader style-loader
add a postcss.config.js
module.exports = {
plugins: {
'postcss-import': {
root: __dirname,
},
'postcss-cssnext': {}
},
};
add a webpack rule
...
{ test: /\.css$/, use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
localIdentName: '[name]--[local]--[hash:base64:8]'
}
},
'postcss-loader'
]},
...
add cmrh.conf.js - Using the css-modules-require-hook for SSR(Optional)
module.exports = {
generateScopedName: '[name]--[local]--[hash:base64:8]'
}
You can see all the settings in here, hope it will work for you.

Resources