Where to register postcss plugin in react app - reactjs

In order to use this package, I think I need to register it. I've already installed it with npm.
I created the project with npx create-react-project my-project. I tried putting in the requirements into index.js like so...
import reportWebVitals from './reportWebVitals';
import postcss from 'postcss';
postcss([ require('postcss-modules-values-replace', require('postcss-calc'))])
But I got an error Cannot statically analyse 'require(...,...) and it looks like it's because I'm supposed to do something with webpack but I don't see any webpack.js files in my project so I'm not sure how to register the plugin.

Place it before other plugins:
postcss([ require('postcss-modules-values-replace'), require('postcss-calc') ]);
create postcss.config.js file and define the plugins
module.exports = (ctx) => ({
plugins: [
require('postcss-modules-values-replace')({fs: ctx.webpack._compiler.inputFileSystem}),
require('postcss-calc'),
]
});

Related

React Uncaught ReferenceError: Buffer is not defined

I created a React project by running npx create-react-app my-app
I installed mqtt-react-hooks
I added the App script
import { Connector } from 'mqtt-react-hooks';
import Status from './Status';
function App() {
return (
<Connector
brokerUrl="mqtt://127.0.0.1:80/"
parserMethod={(msg) => msg} // msg is Buffer
>
<Status />
</Connector>
);
}
export default App;
I get this error in the console
As mentioned in answers here please also consider the following:
npm install --save buffer
import {Buffer} from 'buffer';
It won't help in case of external library dependency but might save you from reverting other libraries in case of using Buffer in code directly.
I had this problem too.
Recently I create a new version of react app and when I used mqtt.js ( not mqtt-react-hooks ) this bad Error was shown!!!
I found out Webpack version 5 does not support Buffer and so on.
Webpack 5 removes Buffer (see this info), effectively breaking MQTT library since it has explicit usages of it in the code.
so I downgrade to Webpack 4 and it's work.
if you don't know how to do that, this link might be helpful.
How to downgrade version of Webpack?.
To me downgrading react-scripts to version 4.0.3 fixed the problem. It is not a proper fix but its something...
In my case I needed to do the following also:
In package.json use react-script 4.0.3
Remove package-lock.json
remove node_modules folder
run npm install
After all this everything seems to be working fine.
In Webpack version 5, Webpack no longer automatically polyfill's Node.js API's if they are not natively supported anymore. The browser environment does not support Buffer natively, therefore we now need to add a third party Buffer package and point Node.js to it in the Webpack config. See how to polyfill buffer with webpack 5.
Use this on the page or function where you get an error:
window.Buffer = window.Buffer || require("buffer").Buffer;
for me what worked was:
import { defineConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
import path from 'path'
import inject from '#rollup/plugin-inject'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'#': path.resolve(__dirname, 'src'),
}
},
build: {
rollupOptions: {
plugins: [inject({ Buffer: ['buffer', 'Buffer'] })],
},
},
})
reply to this comment:
https://github.com/vitejs/vite/discussions/2785#discussioncomment-1452855
the only solution that worked for me was this:
npm add node-stdlib-browser
npm add -D vite-plugin-node-stdlib-browser
and then:
// vite.config.js
import { defineConfig } from 'vite'
import nodePolyfills from 'vite-plugin-node-stdlib-browser'
export default defineConfig({
// other options
plugins: [nodePolyfills()]
})

Unable to resolve an image which is shared between web (react) and mobile (react-native) projects

I have a custom npm package created in directory web_with_weback (web react project). The package is built using webpack and contains one .png image. The package is loaded by using npm link inside another directory which is a react native project named mobile_with_metro. So in short, I want to have an npm package which among other things will share images from web to mobile. So to give you some context, here is how the two projects are setup.
The web project has the following structure.
Where the index.ts contains:
import TestImage from './testimage.png';
export {
TestImage
};
webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
entry: {
images: {import: './src/images/index.ts', filename: 'images/index.js'}
},
externals: [nodeExternals()],
output: {
libraryTarget: 'commonjs'
},
plugins: [
new CleanWebpackPlugin(),
new CopyPlugin({
patterns: [
{ from: "src/images/index.d.ts", to: "images/index.d.ts" }
],
}),
],
module: {
rules: [
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.(png|jpe?g|gif|svg)$/i,
type: 'asset/inline'
}
]
}
}
I use webpack (v5.19.0). I use the latest feature from webapack asset/inline which is a replacement for the previous used url-loader.
dist folder after webpack build looks the following.
By using npm link in the dist folder and npm link #test/web_with_webpack in mobile_with_metro I make the built package available in the mobile app directory.
Now when I try to import the image and render it in an Image component in react native I get the following error:
error: Error: Unable to resolve module `#test/web_with_webpack/images` from `App.tsx`: #test/web_with_webpack/images could not be found within the project or in these directories:
node_modules/#test/web_with_webpack
If you are sure the module exists, try these steps:
1. Clear watchman watches: watchman watch-del-all
2. Delete node_modules: rm -rf node_modules and run yarn install
3. Reset Metro's cache: yarn start --reset-cache
4. Remove the cache: rm -rf /tmp/metro-*
at ModuleResolver.resolveDependency (/home/dpordan/dev/test_webpack_metro/mobile_with_metro/node_modules/metro/src/node-haste/DependencyGraph/ModuleResolution.js:186:15)
at ResolutionRequest.resolveDependency (/home/dpordan/dev/test_webpack_metro/mobile_with_metro/node_modules/metro/src/node-haste/DependencyGraph/ResolutionRequest.js:52:18)
at DependencyGraph.resolveDependency (/home/dpordan/dev/test_webpack_metro/mobile_with_metro/node_modules/metro/src/node-haste/DependencyGraph.js:287:16)
at Object.resolve (/home/dpordan/dev/test_webpack_metro/mobile_with_metro/node_modules/metro/src/lib/transformHelpers.js:267:42)
at /home/dpordan/dev/test_webpack_metro/mobile_with_metro/node_modules/metro/src/DeltaBundler/traverseDependencies.js:434:31
at Array.map (<anonymous>)
at resolveDependencies (/home/dpordan/dev/test_webpack_metro/mobile_with_metro/node_modules/metro/src/DeltaBundler/traverseDependencies.js:431:18)
at /home/dpordan/dev/test_webpack_metro/mobile_with_metro/node_modules/metro/src/DeltaBundler/traverseDependencies.js:275:33
at Generator.next (<anonymous>)
at asyncGeneratorStep (/home/dpordan/dev/test_webpack_metro/mobile_with_metro/node_modules/metro/src/DeltaBundler/traverseDependencies.js:87:24)
Here is the react native App.tsx which imports the image.
import React from 'react';
import {
Image
} from 'react-native';
import {TestImage} from '#test/web_with_webpack/images';
const App = () => {
return (
<>
<Image source={{
uri: TestImage
}}/>
</>
);
};
To me it seems that the metro bundler can't understand what webpack has generated as an image 'path'.
Is there anything that I am missing here?
EDIT:
I tried using it in another react web project (which is setup with CRA) and it works. So, there is something that metro bundler in react native does not understand in the built package.

Storybook - no stories showing up in typescript project with custom webpack / babel

I am trying to set up Storybook in a project. My project is runing on react#^16, and I'm using typescript, with a custom babel and webpack setup for development and build. To set up storybook, I did
npx sb init
This installs everything needed. It puts a .storybook folder in the root folder, and a stories folder in my src folder with some prefab components and stories in tsx format (which is what I want):
The .storybook/main.js file seems fine:
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
],
"addons": [
"#storybook/addon-links",
"#storybook/addon-essentials"
]
}
And the average .stories.js file automatically installed by npx sb init also seems fine:
import React from 'react';
// also exported from '#storybook/react' if you can deal with breaking changes in 6.1
import { Story, Meta } from '#storybook/react/types-6-0';
import { Header, HeaderProps } from './Header';
export default {
title: 'Example/Header',
component: Header,
} as Meta;
const Template: Story<HeaderProps> = (args) => <Header {...args} />;
export const LoggedIn = Template.bind({});
LoggedIn.args = {
user: {},
};
export const LoggedOut = Template.bind({});
LoggedOut.args = {};
But when I run npm run storybook, the storybook landing page has no stories. Even though it had installed some default stories to start playing with. It says:
Oh no! Your Storybook is empty. Possible reasons why:
The glob specified in main.js isn't correct.
No stories are defined in your story files.
As requested, here is a link to the repo so you can dig a bit deeper into the structure, weback config, etc. Note I have not committed the npx sb init changes yet, so you won't see the files there, only my starting point just before running the sb init.
I haven't had any issues getting npx sb init to work with a standard create-react-app, but with my custom webpack build and typescript, its just empty. What's going wrong?
Edit: Additional detail
I realize that just running npx sb init, then npm run storybook throws this error:
ERROR in ./.storybook/preview.js-generated-config-entry.js
Module not found: Error: Can't resolve 'core-js/modules/es.array.filter'
Based on this thread, installing core-js#3 solves the problem and storybook runs, though with no stories.
It seems like the babel plugin transform-es2015-modules-amd doesn't fit right with storybook since sb still uses your babel configuration.
You might need to remove it then it would work:
{
"plugins": [
// "transform-es2015-modules-amd", // Remove this plugin
]
}
If you want to have a special babel configuration for storybook, place it .storybook/.babelrc so the configuration would be simple like this:
.storybook/.babelrc:
{
"presets": ["#babel/preset-env", "#babel/preset-react", "#babel/preset-typescript"]
}
NOTE: You might miss to forget install #babel/preset-typescript to help you transform your typescript code.
Maybe you have problems with the stories path, try to save only "../src/**/*.stories.js" in your config to see if its the reason
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
]
In case of dealing with arcgis-js-api in sb, you have to declare #arcgis/webpack-plugin in storybook's webpack configuration by adding to its config.
Here are a few steps you have to do:
Add webpackFinal property in .storybook/main.js with following content:
const ArcGISPlugin = require('#arcgis/webpack-plugin');
module.exports = {
// ...
webpackFinal: (config) => {
// Add your plugin
config.plugins.push(
new ArcGISPlugin(),
);
// Since this package has used some node's API so you might have to stop using it as client side
config.node = {
...config.node,
process: false,
fs: "empty"
};
return config;
}
};
One more thing to be aware of, some components are importing scss files, so you might need to support it by adding a scss addon '#storybook/preset-scss'
// Install
npm i -D #storybook/preset-scss css-loader sass-loader style-loader
// Add to your current addons
{
addons: ['#storybook/addon-links', '#storybook/addon-essentials', '#storybook/preset-scss'],
}
Like a tmhao2005 say. Storybook still uses your babel configuration. And this is the intended behavior. This thread at github also describes how the fix similar issue.
Updated your config .storybook/main.js.
If you use .babelrc:
babel: async options => ({ ...options, babelrc: false })
Or .babel.config.js:
babel: async options => ({ ...options, configFile: false })

Webpack + `create-react-app` | ProvidePlugin Not Loading React as a Module

* Note: I barely know anything about Webpack.
I want to load the react node module and other modules in Webpack via ProvidePlugin to have global access to them.
I created a create-react-app and ran eject and got access the pre-defined configuration for Webpack create-react-app provides.
I read this post about loading react globally via PluginProvidor and read about PluginProvidor itself in the Webpack docs, where the latter states:
By default, module resolution path is current folder (./**) and node_modules
Based on that, in webpack.config.js, in plugins, I added the following PluginProvidor:
...
plugins: [
new webpack.ProvidePlugin(
{
React: 'react'
}
)
]
...
But it didn't work - in a JSX file when I call React (e.g class MyComponent extends React.Component { ... }) I get an error that says that React isn't defined (and also a React-specfic error that React must be defined in JSX files).
Why doesn't it work? As far as I understand, I'm giving the same identifier I call in my JSX file, and like I mentioned, according to the Webpack docs, to the path of the react module in node_modules - both as required for it to work.
My configuation file: webpack.config.js
It's not a good idea to use ProvidePlugin, and even worse is to eject your CRA.
Instead of ProvidePlugin use globals:
// globals.js
import React from 'react';
window.React = React;
and then import './globals'
import './globals';
// no need import React
import ReactDOM from 'react-dom';
...
For adding plugins to CRA web pack refer to react-app-rewired.
Example of adding a plugin:
/* config-overrides.js */
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
module.exports = function override(config, env) {
if (!config.plugins) {
config.plugins = [];
}
config.plugins.push(new MonacoWebpackPlugin());
return config;
};
Demo:

ant design - huge imports

I'm using ant design library for my react application.
And I've faced with huge imports, that hurts my bundle (currently 1.1 mb in minified version because of ant-design lib).
How can I differently import antd components through all my app?
UPDATE:
Seems antd has some huge or non optimized modules.
Here the thing - only difference is import Datepicker module, and.. boom! + almost 2MB (in dev bundle ofc.)
UPD: the underlying issue seems to be resolved for the new (4.0) version of antd.
Therefore, if you try to resolve this issue for the earlier versions, the recommended way is to migrate onto antd 4
Previous answer:
At the moment, a huge part of antd dist is SVG icons.
There is no official way to deal with it yet (check the issue on github).
But a workaround exists.
Adapt webpack to resolve icons differently. In your webpack config:
module.exports = {
//...
resolve: {
alias: {
"#ant-design/icons/lib/dist$": path.resolve(__dirname, "./src/icons.js")
}
}
};
Create icons.js in the folder src/ or wherever you want it. Be sure it matches the alias path!
In this file, you define which icons antd should include.
export {
default as DownOutline
} from "#ant-design/icons/lib/outline/DownOutline";
It's also possible to do this with react-app-rewired (create-react-app modifications) within config-overrides.js
1) Prevent antd to load the all moment localization.
Add webpack plugin and configure it in webpack.config.js like the follow:
plugins: [
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /ru/),
],
resolve: {
alias: {moment: `moment/moment.js`}
},
target: `web`
}
2) Use the same moment version as in antd library.
3) Use modularized antd
Use babel-plugin-import
// .babelrc or babel-loader option
{
"plugins": [
["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
// `style: true` for less
]
}
I use BundleAnalyzerPlugin to analyze the bundle.
plugins: [new BundleAnalyzerPlugin()]
Looking at the docs
https://ant.design/docs/react/getting-started#Import-on-Demand
there is a recommedation to import individual components on demand.
So, you can try and replace
import { Button} from 'antd'
with
import Button from 'antd/lib/button'
I reduced my bundle size by 500KB by editing config-override.js like so:
config-override.js
const { override, fixBabelImports } = require('customize-cra');
const path = require('path');
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css'
}),
// used to minimise bundle size by 500KB
function(config, env) {
const alias = config.resolve.alias || {};
alias['#ant-design/icons/lib/dist$'] = path.resolve(__dirname, './src/icons.js');
config.resolve.alias = alias;
return config;
}
);
./src/icons.js
/**
* List all antd icons you want to use in your source code
*/
export {
default as SearchOutline
} from '#ant-design/icons/lib/outline/SearchOutline';
export {
default as CloseOutline
} from '#ant-design/icons/lib/outline/CloseOutline';
export {
default as QuestionCircleOutline
} from '#ant-design/icons/lib/outline/QuestionCircleOutline';
export {
default as PlayCircleOutline
} from '#ant-design/icons/lib/outline/PlayCircleOutline';
export {
default as PauseCircleOutline
} from '#ant-design/icons/lib/outline/PauseCircleOutline';
export {
default as LoadingOutline
} from '#ant-design/icons/lib/outline/LoadingOutline';
Before
After
Those few components are certainly not 1.2M together. Looks like you are importing the whole library when you only need a few components.
To get antd to load only the needed modules you should use babel-plugin-import. Check your console log for the "You are using a whole package of antd" warning described at that link.
Check out the docs for Create-React-App for how to implement it if you're using CRA.
Try using code splitting using webpack and react router. It will help you to load the modules asynchronously. This is the only solution helped me to improve the page load time when using ant framework.
Issue which caused large bundle size has been fixed in Ant Design 4.0.
Quoting from the release announcement.
Smaller size
In antd # 3.9.0, we introduced the svg icon ([Why use the svg icon?]
()). The icon API
using the string name cannot be loaded on demand, so the svg icon file
is fully introduced, which greatly increases the size of the packaged
product. In 4.0, we adjusted the icon usage API to support tree
shaking, reducing the default package size of Antant by about 150 KB
(Gzipped).
In order to install Ant Design 4 you have to do following
npm install antd#4.0.0-rc.1
// or in yarn
yarn add antd#4.0.0-rc.1

Resources