so react-dates css worked fine until i moved to css-modules. i tried importing the css file from node modules in index.js files and in the head of the html file but none of them worked.
Any help or suggestion will be greatly appreciated.
This is working perfectly for this problem
In webpack.config.js define a function which checks your file to
decide if it's css module or global; done using getLocalIdent
option.
This is the method that I'm currently using in my setup.
This also requires your files to have some naming convention,
[name].module.css for css modules and [name].css for regular files.
See example below:
// regex to test for modules, loaderUtils is part of webpack dependencies
const cssModuleRegex = new RegExp(/\.module\.(less|css)$/);
const loaderUtils = require("loader-utils");
// inside webpack rules
{
test: /\.(less|css)$/,
use: [
{
loader: CssExtractPlugin.loader,
options: { hot: is_dev, reloadAll: is_dev }
},
{
loader: "css-loader",
options: {
modules: {
localIdentName: '[local]___[hash:base64:5]',
getLocalIdent: getLocalIdent
}
}
},
"postcss-loader",
"less-loader"
]
}
// this is a copy of the default function, modified slightly to achieve our goal
function getLocalIdent(loaderContext, localIdentName, localName, options) {
// return local name if it's a global css file
if (!cssModuleRegex.test(loaderContext.resourcePath)) {
return localName;
}
if (!options.context) {
// eslint-disable-next-line no-param-reassign
options.context = loaderContext.rootContext;
}
const request = path
.relative(options.context, loaderContext.resourcePath)
.replace(/\\/g, '/');
// eslint-disable-next-line no-param-reassign
options.content = `${options.hashPrefix + request}+${localName}`;
// eslint-disable-next-line no-param-reassign
localIdentName = localIdentName.replace(/\[local\]/gi, localName);
const hash = loaderUtils.interpolateName(
loaderContext,
localIdentName,
options
);
return hash
.replace(new RegExp('[^a-zA-Z0-9\\-_\u00A0-\uFFFF]', 'g'), '-')
.replace(/^((-?[0-9])|--)/, '_$1');
}
Source: How to apply global styles with CSS modules in a react app?
Related
I have a react application with a custom Webpack configuration.
After adding Webpack aliases that matches tsconfig.json file compilerOptions->paths field the aliases were recognized by webpack.
Since storybook comes with a built in Webpack configuration, my aliases are not read by Storybook and I'm getting the following error:
Module not found: Error: Can't resolve <path with typescript alias> in <some folder path>
In Storybook main.js file, add the following:
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
module.exports = {
...,
webpackFinal: async (config, { configType }) => {
config.resolve.plugins = [new TsconfigPathsPlugin()];<-- this line
return config;
}
};
You can install tsconfig-paths-webpack-plugin using the following command from the folder in which your application's package.json file resides:
npm i tsconfig-paths-webpack-plugin -D
Solution was derived from this discussion:
https://github.com/storybookjs/storybook/issues/6316
For future vistors of this question, since 15th July of 2022 storybooks can use Vite instead Webpack.
In that case I recommend using vite-tsconfig-paths instead of tsconfig-paths-webpack-plugin. If you are using TS paths in Vite, you probably already have this package installed.
Add this to your .storybook/main.js
const { mergeConfig } = require("vite")
const { default: tsconfigPaths } = require('vite-tsconfig-paths')
module.exports = {
// your previous configs and more...
viteFinal(config, { configType }) {
return mergeConfig(config, {
plugins: [
tsconfigPaths()
]
})
}
}
An alternative to accepted solution:
If you prefer not to install an external library such as tsconfig-paths-webpack-plugin, you can create a custom file, say:
tsconfig-webpack-utils.js
and do something similar to the following:
const { compilerOptions } = require('../tsconfig.json');
function getAliases() {
const baseUrl = getTSBaseUrl();
return Object.fromEntries(Object.entries(compilerOptions.paths).map(([key, value]) => {
return [
key.replace(/\/\*\*?$/,''),
value.map(entryPath => path.resolve(__dirname, baseUrl, entryPath.replace(/\/\*\*?$/,'/')))
]
}));
}
function getTSBaseUrl() {
return path.resolve(__dirname, `../${compilerOptions.baseUrl}`);
}
exports.addTsDefinitionsToWebpack = function(webpackConfig) {
if (!webpackConfig.resolve.modules) {
webpackConfig.resolve.modules = ['node_modules'];
}
webpackConfig.resolve.modules.push(getTSBaseUrl());
webpackConfig.resolve.alias = {
...webpackConfig.resolve.alias,
...getAliases()
};
}
This solution only works for very simple aliases. It is recommended to use an appropriate library or to expand this solution according to your needs.
You can then use it as follows in every webpack config you require it:
addTsDefinitionsToWebpack(webpackConfig);
today I have a very large problem using react & craco, I can't seem to get my webpack-obfuscator to do anything. I have disabled source maps, but to no avail.
This is my craco config:
const path = require("path");
const WebpackObfuscator = require('webpack-obfuscator');
module.exports = {
webpack: {
configure: (webpackConfig) => {
// Because CEF has issues with loading source maps properly atm,
// lets use the best we can get in line with `eval-source-map`
if (webpackConfig.mode === 'development' && process.env.IN_GAME_DEV) {
webpackConfig.devtool = 'eval-source-map'
webpackConfig.output.path = path.join(__dirname, 'build')
}
return webpackConfig
},
plugins: {
add: [
new WebpackObfuscator ({
rotateStringArray: true
}),
],
},
},
devServer: (devServerConfig) => {
if (process.env.IN_GAME_DEV) {
// Used for in-game dev mode
devServerConfig.writeToDisk = true
}
return devServerConfig
}
}
I get no visible maps files when building, and I've put "GENERATE_SOURCEMAP=false" in my .env file that's located where the package.json is.
Hopefully someone has the answer as to why this is happening.
Kind regards, and thanks for reading.
To upgrade a short config, you can use a construct that, if the condition is met, updates the configuration without using WebpackObfuscator:
module.exports = {
webpack: {
configure: {
...(process.env.IN_GAME_DEV && process.env.NODE_ENV === 'development' && {devtool: 'eval-source-map'})
}
}
}
Also, if you need additional properties for the configuration, in addition to the dvttool, you can add them
I'm currently working with next#11.1.2 and webpack v5 and got stuck for hours with fixing mp3 loading. I tried several other solutions from stack and GitHub. None of them worked for me.
Type error: Cannot find module 'public/sounds/bighit.mp3' or its corresponding type declarations.
14 |
15 | // Assets
> 16 | import sound_bighit from "public/sounds/bighit.mp3"
| ^
info - Checking validity of types .%
Here is my last configuration for webpack:
const path = require('path')
const SRC = path.resolve(__dirname, 'public/sounds/')
module.exports = {
webpack: (config, { }) => {
config.module.rules.push({
test: /\.mp3$/,
incluse: SRC,
use: {
loader: 'file-loader',
options: {
name: '[name].[contenthash].[ext]',
outputPath: 'public/sounds/',
publicPath: 'public/sounds/'
}
}
})
// config.module.rules.push({
// test: /\.mp3$/,
// use: {
// loader: 'file-loader',
// },
// })
// config.module.rules.push({
// test: /\.mp3/,
// use: {
// loader: 'url-loader',
// },
// })
return config
}
}
There is no need to import such files. Next.js supports putting the assets in public folder. Remove your custom webpack configuration and then simply do this:
<audio controls src="/sounds/bighit.mp3" />
Refer: Static File Serving
Next.js can serve static files, like images, under a folder called public in the root directory. Files inside public can then be referenced by your code starting from the base URL (/).
Also, the error that you were getting was a TypeError, to fix it you can try:
// types/sounds.d.ts
declare module "*.mp3" {
const content: string;
export default content;
}
Refer: Importing Other Assets | TypeScript - webpack
Is it possible to configure storybook 6 to use the module paths in my tsconfig.json file to work with sass-loader (or just to replicate the same pattern if that's not possible).
Ideally, I'd like to be able to add a sass loader with this option:
additionalData: `
#use '#themes' as vars;
#use '#themes/breakpoints' as bp;
`,
instead of
additionalData: `
#use '../themes' as vars;
#use '../themes/breakpoints' as bp;
`,
My tsconfig.json file has this section in it which works well inside .ts files but obviously doesn't work in sass files:
"paths": {
"#components/*": ["./components/*"]
}
If I could replicate that for themes, that'd be amazing.
Turns out it was pretty easy:
in main.js. Add the following to your module.exports:
webpackFinal: async (config, { configType }) => {
config.resolve.alias = {
...config.resolve.alias,
"#themes": path.resolve(__dirname, "../themes/default")
}
return config;
}
Actually, past Alex, there is a better solution now using the ts-config-paths-webpack-plugin that is automatic and doesn't require repeating config code:
// main.js
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const pathsPlugin = new TsconfigPathsPlugin({
configFile: path.resolve(__dirname, '../tsconfig.json')
})
webpackFinal: async (config) => {
if (config.resolve.plugins) {
config.resolve.plugins.push(pathsPlugin);
} else {
config.resolve.plugins = [pathsPlugin];
}
...
Building a server side react app and while using Webpack I am having issues with Style-Loader.
I am using version "^0.23.1" and when running a script to bundle and build there is an issue from Style-Loader.
The issue is window is not defined
webpack:///./node_modules/style-loader/lib/addStyles.js?:23
return window && document && document.all && !window.atob;
Has anyone run into this issue? After looking through Stack and the Github issues for style-loader I am not finding any solution.
Here is my webpack file:
const path = require('path');
const webpack = require('webpack');
module.exports = {
// webpack to use node
target: 'node',
entry: './src/index.js',
output: {
filename: 'client-build.js',
path: path.resolve(__dirname, 'build/public'),
publicPath: '/build/public'
},
module: {
rules: [
{
test: /\.js$|\.jsx$/,
loader: 'babel-loader',
exclude: '/node_modules/',
options: {
presets: [
'#babel/preset-react'
]
}
},
{
test: /\.(s*)css$/,
loader: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.jpeg$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$|\.wav$|\.mp3$|\.jpg$|\.pdf$/,
loader: 'file-loader',
query: {
name: 'assets/img/[name].[ext]'
},
},
]
},
plugins: [
new webpack.ProvidePlugin({
"React": "react",
}),
],
}
If there is anything else you need to see I can post it.
style-loader tries to inject styles into the head of the website (window / document), which will be non-existent on your server on render / execution.
You need to remove this loader from your server-config and replace it with something else (e.g. ExtractTextPlugin or MiniCSSExtractplugin, depending on your webpack version)
I think your problem is, that there is no window object when running js code on a node server. Which also makes sense, as your server has no window where your code is rendered. You can use the global object for global references instead, see this related post here: Does node.js have equivalent to window object in browser
If I got it correctly I think you are trying to use style-loader for bundling server side code.If it is the case try doing this instead of doing this:
loader: ['style-loader', 'css-loader', 'sass-loader']
Try this:
loader: ['css-loader/locals', 'sass-loader']
Style loader is not supposed to be used on the server side code. So we provide kind of a null-loader instead of css-loader and remove style loader. This should do the trick I guess.
I had a this problem where I needed some themes and styles from a component-library which in turn used webpack and style-loader.
My project was pure script and is supposed to generate some files and therefore had no browser. It would not compile at all since style-loader(and some other libs) tried to inject styles in the tag.
I ended up mocking window and document so that the imported project could compile.
NOTE that this worked in my case where I only needed a minor part of my component-library, if you use this in a more complicated project there will probably be some weird bugs. But it might help someone figure out a similar problem
Run this before you do the actual import
Since it is the actual import that causes the problem you need to do the hack before importing.
import * as Hack from './hack/StyleLoaderHack';
Hack.runHack();
...
import {X} from 'your library'
StyleLoaderHack.js
class HackStyle {
position;
constructor() {
this.position = [];
}
}
class HackElement {
className;
childNodes;
style;
constructor(tag) {
this.className = tag;
this.attributes = [];
this.childNodes = [];
this.style = new HackStyle();
}
appendChild = (child) => {
let append;
if (!(child instanceof HackElement)) {
append = new HackElement(child);
} else {
append = child;
}
this.childNodes.push(append);
return append;
};
insertBefore = (newChild, refChild) => {
let insert;
if (!(newChild instanceof HackElement)) {
insert = new HackElement(newChild);
} else {
insert = child;
}
this.childNodes.push(insert);
};
setAttribute = (qualifiedName, value) => {
// sketchy but works
this.attributes.push(qualifiedName);
this.attributes.push(value);
};
}
class HackDocument {
head;
constructor() {
this.head = new HackElement("head");
}
createElement = (tagName) => {
const element = new HackElement(tagName);
return element;
};
querySelector = (target) => {
const node = new HackElement(target);
return node;
};
querySelectorAll = (target) => {
if (target === "[data-emotion-css]") {
return [];
}
const node = new HackElement(target);
return [node];
};
createTextNode = (data) => {
return new HackElement(data);
};
}
/**
* Adds some function to global which is needed to load style-loader, emotion, create-emotion and react-table-hoc-fixed-columns.
*/
export const runHack = () => {
global.window = {};
const hackDocument = new HackDocument();
global.document = hackDocument;
};