Skip to content

Conversation

bernardobelchior
Copy link
Member

@bernardobelchior bernardobelchior commented Aug 11, 2025

Part of mui/mui-public#481

Noticed that we depend on fs-extra, so tried to replace it with node:fs where possible. Most of the calls to fs-extra were node:fs calls anyway.

After these changes, there are only 4 imports of fs-extra, which we might be able to remove eventually.

import { Symbol, isPropertySignature, isExportSpecifier, TypeFormatFlags } from 'typescript';
import fs from 'node:fs';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imported from node:fs, but we seem to import from fs directly. I can change that if needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm adding mui/mui-public#476

@mui-bot
Copy link

mui-bot commented Aug 11, 2025

Deploy preview: https://deploy-preview-19127--material-ui-x.netlify.app/

Bundle size report

Bundle Parsed Size Gzip Size
@mui/x-data-grid 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-pro 0B(0.00%) 🔺+2B(0.00%)
@mui/x-data-grid-premium 0B(0.00%) 🔺+2B(0.00%)
@mui/x-charts 0B(0.00%) 0B(0.00%)
@mui/x-charts-pro 0B(0.00%) 🔺+2B(0.00%)
@mui/x-date-pickers 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers-pro 0B(0.00%) 🔺+5B(+0.01%)
@mui/x-tree-view 0B(0.00%) 0B(0.00%)
@mui/x-tree-view-pro 0B(0.00%) 🔺+1B(0.00%)

Details of bundle changes

Generated by 🚫 dangerJS against bfb2539

@@ -50,7 +50,8 @@ async function main(argv) {
const exec = dryRun ? execDry : execActual;

const rootWorkspace = getWorkspaceRoot();
const rootWorkspaceManifest = await fse.readJSON(path.join(rootWorkspace, 'package.json'));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readJSON imports ./jsonfile, which imports the jsonfile package.

jsonfile's readFile is implemented here. Since we don't provide any options, it boils down to fs.readFile + JSON.parse(data, null).

stripBom just converts the buffer into an utf8 string, so this code is equivalent.

@bernardobelchior bernardobelchior requested a review from a team August 11, 2025 10:29
@bernardobelchior bernardobelchior marked this pull request as ready for review August 11, 2025 10:29
@@ -97,7 +97,7 @@ export async function writePrettifiedFile(filename: string, data: string) {
);
}

fse.writeFileSync(
fs.writeFileSync(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not

Suggested change
fs.writeFileSync(
await fs.writeFile(

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wanted to keep the changes to a minimum, but I guess this is fine.

import { Symbol, isPropertySignature, isExportSpecifier, TypeFormatFlags } from 'typescript';
import fs from 'node:fs';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we can standardize on

Suggested change
import fs from 'node:fs';
import fs from 'node:fs/promises';

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm ok with that.

@@ -12,7 +12,6 @@
const ignoreList = ['/pages.ts', 'styling.ts', 'styling.tsx', 'types.ts'];

const fs = require('fs');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well just import fs/promises instead of doing fs.promises

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a mixed usage of fs and fs/promises in this file, so that's why I opted for this approach.

We can also do const fsPromises = require('fs/promises'); and migrate the relevant code snippets. What would you prefer?

@@ -50,7 +50,8 @@ async function main(argv) {
const exec = dryRun ? execDry : execActual;

const rootWorkspace = getWorkspaceRoot();
const rootWorkspaceManifest = await fse.readJSON(path.join(rootWorkspace, 'package.json'));
const rootWorkspacePackageJson = await fs.readFile(path.join(rootWorkspace, 'package.json'));
Copy link
Member

@Janpot Janpot Aug 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe with a proper encoding it will always return a string

Suggested change
const rootWorkspacePackageJson = await fs.readFile(path.join(rootWorkspace, 'package.json'));
const rootWorkspacePackageJson = await fs.readFile(path.join(rootWorkspace, 'package.json'), 'utf-8');

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. If we do that, to maintain a 100% compatible change, we'd need to handle byte order mark as jsonfile does.

I'm not very familiar with this, so I'm not sure how big of a problem it might be.

From my tests, our root package.json does not use BOM, but it might be dependent on the last person who made changes to that specific file.

From the UTF-8 spec:

A protocol SHOULD forbid use of U+FEFF as a signature for those
textual protocol elements that the protocol mandates to be always
UTF-8, the signature function being totally useless in those
cases.

So I think we can ignore it and assume we're always using UTF-8

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've been consuming json files all over the place with this method since forever, so I'm not really concerned. I'm adding the unicode-bom rule in the ticket

@bernardobelchior bernardobelchior merged commit 1947126 into mui:master Aug 11, 2025
20 checks passed
@bernardobelchior bernardobelchior deleted the replace-fs-extra-where-possible branch August 11, 2025 12:31
@@ -90,15 +89,18 @@ const previewOverride = {
async function transpileFile(tsxPath, program, ignoreCache = false) {
const jsPath = tsxPath.replace(/\.tsx?$/, '.js');
try {
if (!ignoreCache && (await fse.exists(jsPath))) {
const [jsStat, tsxStat] = await Promise.all([fse.stat(jsPath), fse.stat(tsxPath)]);
if (!ignoreCache && (await fs.promises.exists(jsPath))) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line introduced an issue. Fix here

@zannager zannager added the scope: docs-infra Changes related to the docs-infra product. label Aug 11, 2025
@Janpot Janpot added scope: code-infra Changes related to the core-infra product. and removed scope: docs-infra Changes related to the docs-infra product. labels Aug 11, 2025
@oliviertassinari oliviertassinari added the type: enhancement It’s an improvement, but we can’t make up our mind whether it's a bug fix or a new feature. label Aug 17, 2025
@zannager zannager changed the title [infra] Replace fs-extra with node:fs where possible [code-infra] Replace fs-extra with node:fs where possible Aug 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
scope: code-infra Changes related to the core-infra product. type: enhancement It’s an improvement, but we can’t make up our mind whether it's a bug fix or a new feature.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants