Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrating to Pigment CSS with react/webpack #43597

Open
clairefields15 opened this issue Sep 3, 2024 · 15 comments · Fixed by mui/pigment-css#286
Open

Migrating to Pigment CSS with react/webpack #43597

clairefields15 opened this issue Sep 3, 2024 · 15 comments · Fixed by mui/pigment-css#286
Assignees
Labels
package: pigment-css Specific to @pigment-css/* support: docs-feedback Feedback from documentation page

Comments

@clairefields15
Copy link

clairefields15 commented Sep 3, 2024

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

@clairefields15 clairefields15 added status: waiting for maintainer These issues haven't been looked at yet by a maintainer support: docs-feedback Feedback from documentation page labels Sep 3, 2024
@mnajdova
Copy link
Member

mnajdova commented Sep 3, 2024

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.

@DiegoAndai DiegoAndai added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Sep 4, 2024
@clairefields15
Copy link
Author

clairefields15 commented Sep 5, 2024

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 ()
at [path-to-node-modules]/@wyw-in-js/transform/lib/transform/actions/BaseAction.js:66:78
at EventEmitter.action ([path-to-node-modules]/@wyw-in-js/transform/lib/utils/EventEmitter.js:25:22)
at BaseAction.emitAction ([path-to-node-modules]/@wyw-in-js/transform/lib/transform/actions/BaseAction.js:131:39)
at nextFn ([path-to-node-modules]/@wyw-in-js/transform/lib/transform/actions/BaseAction.js:66:32)
at processNext ([path-to-node-modules]/@wyw-in-js/transform/lib/transform/actions/BaseAction.js:111:28)
at Object.next ([path-to-node-modules]/@wyw-in-js/transform/lib/transform/actions/BaseAction.js:120:9)
at asyncActionRunner ([path-to-node-modules]/@wyw-in-js/transform/lib/transform/actions/actionRunner.js:39:102)
at async asyncActionRunner ([path-to-node-modules]/@wyw-in-js/transform/lib/transform/actions/actionRunner.js:46:22)
at async Object.transform ([path-to-node-modules]/@wyw-in-js/transform/lib/transform.js:107:20)
at async Object.transform ([path-to-node-modules]/@pigment-css/unplugin/build/index.js:268:24)
at async Object.transform ([path-to-node-modules]/@pigment-css/unplugin/node_modules/unplugin/dist/webpack/loaders/transform.js:114:15)

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Sep 5, 2024
@zannager zannager added the package: pigment-css Specific to @pigment-css/* label Sep 6, 2024
@clairefields15
Copy link
Author

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.

@brijeshb42
Copy link
Contributor

@clairefields15 Could you share a repo for me to take a look at ?

@brijeshb42 brijeshb42 added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Sep 9, 2024
@clairefields15
Copy link
Author

clairefields15 commented Sep 12, 2024

@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

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Sep 12, 2024
@clairefields15
Copy link
Author

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

@arananegra
Copy link

I'm also struggling with migration a webpack + typescript project to pigment-css. It would be nice if a webpack guide could be included in https://mui.com/material-ui/migration/migrating-to-pigment-css/

@brijeshb42
Copy link
Contributor

Hey all, an update on this. While I was able to fix the config to work with Webpack, I found an issue that is in the core right now that relates to how we do sx prop transform and it's relation to mangling. This affects all the bundlers and not just webpack but is more prominent for Webpack.
I'll provide an update once I fix it.

Copy link

This issue has been closed. If you have a similar problem but not exactly the same, please open a new issue.
Now, if you have additional information related to this issue or things that could help future readers, feel free to leave a comment.

Note

@clairefields15 How did we do? Your experience with our support team matters to us. If you have a moment, please share your thoughts in this short Support Satisfaction survey.

@github-actions github-actions bot removed the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Oct 24, 2024
@brijeshb42 brijeshb42 reopened this Oct 24, 2024
@brijeshb42
Copy link
Contributor

Reopening as the PR only fixes the issue partially. I'll add a proper fix for your specific code.

@brijeshb42
Copy link
Contributor

@clairefields15 Can you try with the latest version of Pigment CSS packages v0.0.25.

One extra change I'd add to your source is add

import '@mui/material-pigment-css/styles.css'

in src/index.tsx.

You might have to add a version override for @pigment-css/react to 0.0.25 for time being till a new version of @mui/material-pigment-css is published.

I was able to test dev server and built files with these changes locally.

@clairefields15
Copy link
Author

@brijeshb42 thank you for looking at this! We will give it a try in the real repo and let you know how it goes.

@pszujewski
Copy link

pszujewski commented Oct 29, 2024

@brijeshb42 thanks again for looking into this. I've been looking into this issue with @clairefields15. Unfortunately, After following the steps you outlined above, we're still encountering the same error message as follows. We're on Windows OS by the way and using node v20.15.1.

node:internal/process/promises:391
    triggerUncaughtException(err, true /* fromPromise */);
    ^
<path>\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') in<path>\node_modules\@mui\material\node\index.js | <path>\packages\host\src\<someComponent>.tsx
    at Module.evaluate (<path>\node_modules\@wyw-in-js\transform\lib\module.js:224:13)
    at require.Object.assign.ensure (<path>\node_modules\@wyw-in-js\transform\lib\module.js:118:7)
    at newRequire (<path>\node_modules\@pigment-css\unplugin\build\index.js:104:12)
    at <path>\packages\host\src\<someComponent>.tsx:8:17
    at <path>\packages\host\src\<someComponent>.tsx:52:3
    at Script.runInContext (node:vm:148:12)
    at Module.evaluate (<path>\node_modules\@wyw-in-js\transform\lib\module.js:209:14)
    at evaluate (<path>\node_modules\@wyw-in-js\transform\lib\evaluators\index.js:14:5)
    at BaseAction.evalFile (<path>\node_modules\@wyw-in-js\transform\lib\transform\generators\evalFile.js:35:43)        
    at evalFile.next (<anonymous>)
    at <path>\node_modules\@wyw-in-js\transform\lib\transform\actions\BaseAction.js:66:78

I also saw the error reported as follows while debugging, which seems a little more helpful:

<path>\node_modules\@mui\material\node\styles\index.js:57
    return _system.StyledEngineProvider;
                   ^

TypeError: Cannot read properties of undefined (reading 'StyledEngineProvider')
    at Object.get (<path>\node_modules\@mui\material\node\styles\index.js:57:20)
    at exports.<computed> (<path>\node_modules\@wyw-in-js\transform\lib\transform\BaseEntrypoint.js:90:127)
    at exports.<computed> (<path>\node_modules\@wyw-in-js\transform\lib\transform\BaseEntrypoint.js:84:20)
    at exports.<computed> (<path>\node_modules\@wyw-in-js\transform\lib\transform\BaseEntrypoint.js:84:20)
    at exports.<computed> (<path>\node_modules\@wyw-in-js\transform\lib\transform\BaseEntrypoint.js:84:20)
    at exports.<computed> (<path>\node_modules\@wyw-in-js\transform\lib\transform\BaseEntrypoint.js:84:20)
    at exports.<computed> (<path>\node_modules\@wyw-in-js\transform\lib\transform\BaseEntrypoint.js:84:20)
    at exports.<computed> (<path>\node_modules\@wyw-in-js\transform\lib\transform\BaseEntrypoint.js:84:20)
    at exports.<computed> (<path>\node_modules\@wyw-in-js\transform\lib\transform\BaseEntrypoint.js:84:20)
    at exports.<computed> (<path>\node_modules\@wyw-in-js\transform\lib\transform\BaseEntrypoint.js:84:20) {stack: '<path>…orm\\lib\\transform\\BaseEntrypoint.js:84:20)', message: "Cannot read properties of undefined (reading 'StyledEngineProvider')"}

If I set a breakpoint at line 57, I hit the breakpoint a bunch of times and _system is defined and everything looks good. Eventually though, I hit the error above and _system is undefined (in fact all the requires in that file are undefined). I added the try/catch for debugging purposes:

Object.defineProperty(exports, "StyledEngineProvider", {
  enumerable: true,
  get: function () {
      return _system.StyledEngineProvider;
  }
});

image

But before I hit this error, when execution stops at this breakpoint, things look correct:

image

The error above always reports that this error is emanating from a component in my source that imports Grid or Box so maybe it has something to do with those components? For example, one of the components I'm referring to has these MUI imports:

import { Input, Button, MenuItem, Select, InputLabel } from '@mui/material';
import Grid from '@mui/material-pigment-css/Grid';

import Add from '@mui/icons-material/Add';
import Delete from '@mui/icons-material/Delete';

Just to confirm, we included this in our source:

import '@mui/material-pigment-css/styles.css';

We added a version override for @pigment-css/react:

"overrides": {
	"@pigment-css/react": "0.0.25"
},

We double checked and confirmed that version 0.0.25 was the only installed version of that package in our project.

Otherwise we followed the Pigment CSS migration guide closely. I was wondering a couple things though as I went through the guide. Looking at the error it doesn't seem like it's necessarily related to any of these things, but I just wanted to check some assumptions while as I was posting this anyway in case something stands out:

  • All the imports in the migration guide for @mui/material are default imports like import Example from @mui/material/Example. But in our project, the imports tend to be named imports like: import { Example } from "@mui/material". Not sure if this could be an issue? I imagine not, but seems worth double checking if you could confirm.

  • In the first response to this thread, it's suggested that we use const { createTheme } = require('@mui/material') for the theme provided to the PigmentPlugin. But in the example linked in that same comment, you can see that const { extendTheme } = require('@pigment-css/unplugin'); is used instead. Which one should we use for the theme given to the PigmentPlugin?

  • We had a number of instances where sx values depended on runtime state or variables. I updated those to use css variables as suggested in the guide. But I wanted to double check that Pigment is able to handle situations like this?

const defaultSx: SxProps = { color: "#fff", /* etc... */ };

function Example({ sx }: { sx?: SxProps }) {
     return (
         <Box sx={sx ?? defaultSx} />
     );
}

and

import { anotherSxObj } from "../Elsewhere";

const defaultSx: SxProps = { ...anotherSxObj, color: "#fff", /* etc... */ };   // would pigment handle this ok?

function Example({ sx }: { sx: SxProps }) {
     return (
         <Box sx={{ ...defaultSx, ...sx }} />  // and this?
     );
}

I'll try and debug it some more to see if anything else stands out. Thanks again for the help. I can also work again on trying to reproduce the bug in a repo that I can share.

@brijeshb42
Copy link
Contributor

@pszujewski Is it the same code that you've posted in the repo ? If not, can you update the repo with the latest code.

  • Import path should not be an issue. It they are, then it is a bug that needs to be fixed in Pigment CSS
  • When using @mui/material, the theme should come from the same package. If not then you can use extendTheme from @pigment-css/unplugin.
  • Pigment does static analysis of sx prop. So there is no concept of sx props at runtime. All the usage of sx is converted into className and style.
const defaultSx: SxProps = { color: "#fff", /* etc... */ };

function Example({ sx }: { sx?: SxProps }) {
     return (
         <Box sx={sx ?? defaultSx} />
     );
}

Here, sx={sx ?? defaultSx} won't work since sx's value is coming from runtime. However,
sx={defaultSx} will work since defaultSx already has a fixed value. Even

sx={{
  ...defaultSx,
  color: 'red',
  backgroundColor: props.red
}}

will work.

Same is valid for your other example.

sx={{ ...defaultSx }} will work but sx={{ ...defaultSx, ...sx }} won't work.

@pszujewski
Copy link

Thanks, @brijeshb42. No the screenshots and error summaries were from trying to integrate pigment/mui v6 into a private repo.

Nevertheless, we were able to reproduce the same error in the public test repo @clairefields15 created here: https://github.com/clairefields15/webpacktest. Have you tried this repo out? The error is the same as above:

EvalError: Cannot read properties of undefined (reading 'StyledEngineProvider')

However, we weren't able to reproduce the error every time we ran webpack + pigment in this test project. Only a few times. In our private repo it occurs every time. So I will work on trying to get the error to more reliably occur in the public test repo, and I will also update the public test repo to use this newer version of "@pigment-css/react": "0.0.25".

I'll post here again next week as I look into this further starting from this public test repo: https://github.com/clairefields15/webpacktest

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: pigment-css Specific to @pigment-css/* support: docs-feedback Feedback from documentation page
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

7 participants