Open clairefields15 opened 1 week ago
Yes you can, you can use the @pigment-css/unplugin
package.
Here is an example webpack.config.js
file:
const { webpack: PigmentPlugin } = require('@pigment-css/unplugin');
const { createTheme } = '@mui/material';
// your custom Material UI theme
const theme = createTheme({ cssVariables: true });
module.exports = {
// other config
plugins: [
PigmentPlugin({
theme,
transformLibraries: ['@mui/material'],
}),
// other plugins
],
};
We have one example in the Pigment CSS repo, but we should likely add one for Material UI as well. Let me know if the example above is enough for your use-case.
Thanks for the response! This did not seem to be enough for our use case, however. Here is our full webpack.config:
const fs = require('fs');
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const Dotenv = require('dotenv-webpack');
const { webpack: PigmentPlugin } = require('@pigment-css/unplugin');
const { createTheme } = require('@mui/material');
const AccentBlue = '#005373';
const AccentOrange = '#fc601f';
const Gray = '#d2d6d8';
const White = '#ffffff';
const theme = createTheme({
cssVariables: true,
palette: {
primary: {
main: AccentOrange,
light: White,
},
secondary: {
main: AccentBlue,
},
background: {
default: Gray,
},
},
typography: {
fontSize: 12,
fontFamily: ['Open sans', 'Verdana', 'Sans Serif'].join(','),
allVariants: {
fontSize: 12,
fontFamily: ['Open sans', 'Verdana', 'Sans Serif'].join(','),
},
},
zIndex: {
drawer: 920000,
modal: 930000,
snackbar: 940000,
tooltip: 950000,
},
components: {
MuiAutocomplete: {
styleOverrides: {
listbox: {
'.MuiAutocomplete-option[aria-selected="false"].Mui-focused':
{
backgroundColor: Gray,
},
'.MuiAutocomplete-option[aria-selected="false"].Mui-focusVisible':
{
backgroundColor: Gray,
},
'.MuiAutocomplete-option[aria-selected="false"].Mui-focused.Mui-focusVisible':
{
backgroundColor: Gray,
},
},
},
},
MuiChip: {
styleOverrides: {
colorPrimary: {
'&.Mui-disabled': {
color: '#000000',
backgroundColor: Gray,
opacity: 0.8,
},
},
colorSecondary: {
color: '#FFFFFF',
backgroundColor: AccentBlue,
},
},
},
MuiCircularProgress: {
styleOverrides: {
circle: {
color: 'grey',
},
},
},
MuiTypography: {
styleOverrides: {
root: {
fontFamily: ['Open sans', 'Verdana', 'Sans Serif'].join(
',',
),
},
},
},
MuiButton: {
styleOverrides: {
root: {
fontFamily: ['Open sans', 'Verdana', 'Sans Serif'].join(
',',
),
},
},
},
MuiToggleButton: {
styleOverrides: {
root: {
padding: '0px 7px',
},
},
},
},
});
// App directory
const appDirectory = fs.realpathSync(process.cwd());
// Gets absolute path of file within app directory
const resolveAppPath = (relativePath) =>
path.resolve(appDirectory, relativePath);
// Host
const host = process.env.HOST || 'local.edelweiss.plus';
const sassLoader = {
loader: 'sass-loader',
};
module.exports = ({ mode, env }) => {
const isModeProduction = mode === 'production';
const styleLoader = {
loader: isModeProduction ? MiniCssExtractPlugin.loader : 'style-loader',
};
const getEnv = () => {
if (mode === 'development' && fs.existsSync('./.env.local')) {
return 'local';
}
return env;
};
const getOutputFileName = () => {
return isModeProduction
? 'static/js/[name].[contenthash:8].js'
: 'static/js/bundle.js';
};
return {
mode,
entry: './src/index.tsx',
output: {
library: 'EdelweissComponents',
path: path.resolve(__dirname, 'build'),
filename: getOutputFileName(),
},
devtool: isModeProduction ? undefined : 'eval-source-map',
ignoreWarnings: [
{
message:
/mini-css-extract-plugin[^]*Conflicting order. Following module has been added:/,
},
],
devServer: {
// Serve index.html as the base
static: {
directory: resolveAppPath('public'),
},
// Enable compression
compress: true,
// Enable hot reloading
hot: true,
host,
server: 'https',
port: 3000,
allowedHosts: ['localhost:9999', 'local.edelweiss.plus'],
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Headers':
'Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Traceparent, Request-Id',
'Access-Control-Allow-Methods':
'GET, POST, PUT, DELETE, OPTIONS',
},
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
options: { configFile: 'tsconfig.json' },
},
{
test: /\.(sc|c)ss$/i,
exclude: /\.module\.(sc|c)ss$/i,
use: [
styleLoader,
{
loader: 'css-loader',
},
sassLoader,
],
},
{
test: /\.module\.(sc|c)ss$/i,
use: [
styleLoader,
{
loader: 'css-loader',
options: {
sourceMap: false,
modules: {
localIdentName: '[local]___[hash:base64:5]',
exportLocalsConvention: 'camelCaseOnly',
},
},
},
sassLoader,
],
},
],
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
},
plugins: [
PigmentPlugin({
theme,
meta: { type: 'webpack' },
babelOptions: {
presets: [
'@babel/preset-env',
'@babel/preset-react',
'@babel/preset-typescript',
],
},
transformLibraries: ['@mui/material'],
}),
new HtmlWebpackPlugin({
inject: true,
scriptLoading: 'blocking',
template: resolveAppPath('public/index.html'),
}),
new Dotenv({
path: `./.env.${getEnv()}`,
}),
].concat(isModeProduction ? [new MiniCssExtractPlugin()] : []),
optimization: {
minimize: isModeProduction,
minimizer: [
// This is only used in production mode
new TerserPlugin({
terserOptions: {
parse: {
// we want terser to parse ecma 8 code. However, we don't want it
// to apply any minfication steps that turns valid ecma 5 code
// into invalid ecma 5 code. This is why the 'compress' and 'output'
// sections only apply transformations that are ecma 5 safe
// https://github.com/facebook/create-react-app/pull/4234
ecma: 8,
},
compress: {
ecma: 5,
warnings: false,
// Disabled because of an issue with Uglify breaking seemingly valid code:
// https://github.com/facebook/create-react-app/issues/2376
// Pending further investigation:
// https://github.com/mishoo/UglifyJS2/issues/2011
comparisons: false,
// Disabled because of an issue with Terser breaking valid code:
// https://github.com/facebook/create-react-app/issues/5250
// Pending futher investigation:
// https://github.com/terser-js/terser/issues/120
inline: 2,
},
mangle: {
safari10: true,
},
output: {
ecma: 5,
comments: false,
// Turned on because emoji and regex is not minified properly using default
// https://github.com/facebook/create-react-app/issues/2488
ascii_only: true,
},
},
}),
],
},
performance: false,
};
};
And the error I am seeing when I try to run the project:
[BABEL] Note: The code generator has deoptimised the styling of [path-to-node-modules]/@mui/icons-material/esm/index.js as it exceeds the max of 500KB.
node:internal/process/promises:289
triggerUncaughtException(err, true / fromPromise /);
^
[path-to-node-modules]/@wyw-in-js/transform/lib/module.js:224
throw new EvalError(${e.message} in${this.callstack.join('\n| ')}
);
^
EvalError: Cannot read properties of undefined (reading 'StyledEngineProvider') in [path-to-node-modules]/@mui/material/node/index.js
| [path-to-file]/CreateOrEditOrderForm/CreateOrEditOrderStepOne.tsx
at Module.evaluate ([path-to-node-modules]/@wyw-in-js/transform/lib/module.js:224:13)
at require.Object.assign.ensure ([path-to-node-modules]/@wyw-in-js/transform/lib/module.js:118:7)
at newRequire ([path-to-node-modules]/@pigment-css/unplugin/build/index.js:104:12)
at [path-to-file]/CreateOrEditOrderForm/CreateOrEditOrderStepOne.tsx:7:17
at [path-to-file]/CreateOrEditOrderForm/CreateOrEditOrderStepOne.tsx:70:3
at Script.runInContext (node:vm:134:12)
at Module.evaluate ([path-to-node-modules]/@wyw-in-js/transform/lib/module.js:209:14)
at evaluate ([path-to-node-modules]/@wyw-in-js/transform/lib/evaluators/index.js:14:5)
at BaseAction.evalFile ([path-to-node-modules]/@wyw-in-js/transform/lib/transform/generators/evalFile.js:35:43)
at evalFile.next (
I switched from named to default imports for all my mui icons and it resolved this error:
[BABEL] Note: The code generator has deoptimised the styling of [path-to-node-modules]/@mui/icons-material/esm/index.js as it exceeds the max of 500KB.
@clairefields15 Could you share a repo for me to take a look at ?
@brijeshb42 this was a bit challenging, because the repo is an enterprise project so I can't share all of it. I was able to spin up a small project with a very similar structure and when I added the <CloseModalButton/>
component, saw an error that pointed to the same @wyw-in-js
package as I am seeing in my enterprise project. Here is a link to the repo:
https://github.com/clairefields15/webpacktest
I will continue to add components to the repo to attempt to replicate the same error as I see in my other project. In the other project I see:
C:\node_modules\@wyw-in-js\transform\lib\module.js:224
throw new EvalError(`${e.message} in${this.callstack.join('\n| ')}\n`);
^
EvalError: Cannot read properties of undefined (reading 'StyledEngineProvider') inC:\node_modules\@mui\material\node\index.js
In the test repo I see
C:\@wyw-in-js\transform\lib\module.js:224
throw new EvalError(`${e.message} in${this.callstack.join('\n| ')}\n`);
^
EvalError: _interopRequireDefault is not a function inC:\node_modules\@mui\material\node\styles\createPalette.js
I updated this test repo and the error with the StyledEngineProvider occurred the first time I tried to run the app with the modal component included. Commenting the modal component in and out can sometimes reproduces the error, but it is inconsistent. What is consistent is an error "cannot read properties of undefined (reading 'modal')" which is mystifying because I don't personally see anything wrong in the code. When I console.log theme
however it is undefined? So I am wondering if the import for useTheme that was suggested in the pigment migration guide would be different for pigment/unplugin
Related page
https://mui.com/material-ui/migration/migrating-to-pigment-css/
Kind of issue
Unclear explanations
Issue description
Is it possible to migrate to pigment css in a project that uses react/webpack? For various reasons, our project cannot use nextjs or vite but we would like to take advantage of the performance improvements of pigment.
Context
No response
Search keywords: pigment, react, webpack