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

[pickers] Add "use client" directive to every public component and hook #14562

Merged
merged 7 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,12 @@ jobs:
- run:
name: '`pnpm l10n` changes committed?'
command: git add -A && git diff --exit-code --staged
- run:
name: Sync RSC "use client" directives
command: pnpm rsc:build
- run:
name: '`pnpm rsc:build` changes committed?'
command: git add -A && git diff --exit-code --staged
- run:
name: '`pnpm docs:link-check` changes committed?'
command: |
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"prettier:all": "prettier --write . --ignore-path .eslintignore",
"prettier:check": "prettier --check . --ignore-path .eslintignore",
"proptypes": "cross-env BABEL_ENV=development babel-node -i \"/node_modules/(?!@mui)/\" -x .ts,.tsx,.js ./docs/scripts/generateProptypes.ts",
"rsc:build": "tsx ./packages/rsc-builder/buildRsc.ts",
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be part of CI? 🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

It is not in the core, but it would be a nice addition
I'm trying to add it 👍

Choose a reason for hiding this comment

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

It might be a tricky process to do in CI since you'll then want the code to be committed back.
Ideally, it should be part of the build (or did you mean build) ?

Copy link
Member Author

Choose a reason for hiding this comment

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

The CI reminds you to run the script locally anytime you create a new public component (if you did not add "use client" manually).
Similar to what we have for pnpm l10n, it does not commit the localization files but it makes sure we don't forget to do it.

Copy link
Member

Choose a reason for hiding this comment

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

@brijeshb42
It is either part of the build, and we don't commit anything, or it can be a check, where if there are changes after the script is run, the CI fails.

"size:snapshot": "node --max-old-space-size=2048 ./scripts/sizeSnapshot/create",
"size:why": "pnpm size:snapshot --analyze --accurateBundles",
"tc": "node test/cli.js",
Expand Down
147 changes: 147 additions & 0 deletions packages/rsc-builder/buildRsc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import path from 'path';
import * as yargs from 'yargs';
import * as fse from 'fs-extra';
import findComponents from '@mui-internal/api-docs-builder/utils/findComponents';
import findHooks from '@mui-internal/api-docs-builder/utils/findHooks';

type CommandOptions = { grep?: string };

type Project = {
name: string;
rootPath: string;
additionalPaths?: string[];
additionalFiles?: string[];
ignorePaths?: string[];
};

const PROJECTS: Project[] = [
{
name: 'x-date-pickers',
rootPath: path.join(process.cwd(), 'packages/x-date-pickers'),
},
{
name: 'x-date-pickers-pro',
rootPath: path.join(process.cwd(), 'packages/x-date-pickers-pro'),
},
];

async function processFile(
filename: string,
options: {
lineToPrepend?: string;
} = {},
) {
if (!fse.statSync(filename).isFile()) {
return;
}

const { lineToPrepend = `'use client';` } = options;
const contents = await fse.readFile(filename, 'utf8');

if (
filename.indexOf('internal') !== -1 ||
!!contents.match(/@ignore - internal component\./) ||
!!contents.match(/@ignore - internal hook\./) ||
!!contents.match(/@ignore - do not document\./)
) {
return;
}

const lines = contents.split(/\r?\n/);
if (lines[0] === lineToPrepend) {
return;
}

const newContents = `${lineToPrepend}\n${contents}`;

await fse.writeFile(filename, newContents);
}

async function findAll(
directories: string[],
grep: RegExp | null,
findFn: typeof findComponents | typeof findHooks,
) {
const result = await Promise.all(
directories.map((dir) => {
return findFn(dir).filter((item) => {
if (grep === null) {
return true;
}
return grep.test(item.filename);
});
}),
);

return result.flat();
}

async function run(argv: yargs.ArgumentsCamelCase<CommandOptions>) {
const grep = argv.grep == null ? null : new RegExp(argv.grep);

await PROJECTS.reduce(async (resolvedPromise, project) => {
await resolvedPromise;

const projectSrc = path.join(project.rootPath, 'src');

let directories = [projectSrc];

if (Array.isArray(project?.additionalPaths)) {
directories = [
...directories,
...project.additionalPaths.map((p) => path.join(project.rootPath, p)),
];
}

const components = await findAll(directories, grep, findComponents);

components.forEach(async (component) => {
try {
if (!project.ignorePaths?.some((p) => component.filename.includes(p))) {
processFile(component.filename);
}
} catch (error: any) {
error.message = `${path.relative(process.cwd(), component.filename)}: ${error.message}`;
throw error;
}
});

const hooks = await findAll(directories, grep, findHooks);

hooks.forEach(async (hook) => {
try {
processFile(hook.filename);
} catch (error: any) {
error.message = `${path.relative(process.cwd(), hook.filename)}: ${error.message}`;
throw error;
}
});

if (Array.isArray(project?.additionalFiles)) {
project.additionalFiles.forEach(async (file) => {
const fullPath = path.join(project.rootPath, file);
processFile(fullPath);
});
}

return Promise.resolve();
}, Promise.resolve());
}

yargs
.command({
command: '$0',
describe: 'prepends the use client directive to components',
builder: (command) => {
return command.option('grep', {
description:
'Only process files for component filenames matching the pattern. The string is treated as a RegExp.',
type: 'string',
});
},
handler: run,
})
.help()
.strict(true)
.version(false)
.parse();
14 changes: 14 additions & 0 deletions packages/rsc-builder/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "rsc-builder",
"version": "1.0.0",
"private": "true",
"main": "./buildRsc.ts",
"dependencies": {
"fs-extra": "^11.2.0",
"yargs": "^17.7.2"
},
"devDependencies": {
"@types/mocha": "^10.0.7",
"@types/node": "^20.14.8"
}
}
27 changes: 27 additions & 0 deletions packages/rsc-builder/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"compilerOptions": {
"allowJs": true,
"isolatedModules": true,
"noEmit": true,
"noUnusedLocals": false,
"resolveJsonModule": true,
"skipLibCheck": true,
"esModuleInterop": true,
"types": ["node", "mocha"],
"target": "ES2020",
"module": "CommonJS",
"moduleResolution": "node",
"strict": true,
"baseUrl": "./",
"paths": {
"@mui-internal/api-docs-builder": [
"../../node_modules/@mui/monorepo/packages/api-docs-builder/index.ts"
],
"@mui-internal/api-docs-builder/*": [
"../../node_modules/@mui/monorepo/packages/api-docs-builder/*"
]
}
},
"include": ["./**/*.ts", "./**/*.js"],
"exclude": ["node_modules"]
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import useEventCallback from '@mui/utils/useEventCallback';
import { MuiPickersAdapter, PickersTimezone, PickerValidDate } from '@mui/x-date-pickers/models';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import useMediaQuery from '@mui/material/useMediaQuery';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import { refType } from '@mui/utils';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import { PickerViewRendererLookup } from '@mui/x-date-pickers/internals';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import { PickerViewRendererLookup } from '@mui/x-date-pickers/internals';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import { refType } from '@mui/utils';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import { clsx } from 'clsx';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import { styled } from '@mui/material/styles';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import MuiTextField from '@mui/material/TextField';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import { useField, useDefaultizedDateField } from '@mui/x-date-pickers/internals';
import { useSplitFieldProps } from '@mui/x-date-pickers/hooks';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import MuiTextField from '@mui/material/TextField';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import { useField, useDefaultizedDateTimeField } from '@mui/x-date-pickers/internals';
import { useSplitFieldProps } from '@mui/x-date-pickers/hooks';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import MuiTextField from '@mui/material/TextField';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import { useField, useDefaultizedTimeField } from '@mui/x-date-pickers/internals';
import { useSplitFieldProps } from '@mui/x-date-pickers/hooks';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import { PickerViewRendererLookup } from '@mui/x-date-pickers/internals';
Expand Down
1 change: 1 addition & 0 deletions packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import useEventCallback from '@mui/utils/useEventCallback';
import { SlideDirection } from './PickersSlideTransition';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import { ValidateDateProps, validateDate } from '../validation';
import { useLocalizationContext } from '../internals/hooks/useUtils';
Expand Down
1 change: 1 addition & 0 deletions packages/x-date-pickers/src/DateField/DateField.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import MuiTextField from '@mui/material/TextField';
Expand Down
1 change: 1 addition & 0 deletions packages/x-date-pickers/src/DateField/useDateField.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import {
singleItemFieldValueManager,
singleItemValueManager,
Expand Down
1 change: 1 addition & 0 deletions packages/x-date-pickers/src/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import useMediaQuery from '@mui/material/useMediaQuery';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import MuiTextField from '@mui/material/TextField';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import {
singleItemFieldValueManager,
singleItemValueManager,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import useMediaQuery from '@mui/material/useMediaQuery';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import { useRtl } from '@mui/system/RtlProvider';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import resolveComponentProps from '@mui/utils/resolveComponentProps';
Expand Down
Loading