Skip to content

Commit

Permalink
Add react-dsfr index CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
garronej committed Jul 18, 2024
1 parent a02af5a commit 913c43a
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 57 deletions.
14 changes: 7 additions & 7 deletions .storybook/manager-head.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<link rel="apple-touch-icon" href="%PUBLIC_URL%/dsfr/favicon/apple-touch-icon.png" />
<link rel="icon" href="%PUBLIC_URL%/dsfr/favicon/favicon.svg" type="image/svg+xml" />
<link rel="shortcut icon" href="%PUBLIC_URL%/dsfr/favicon/favicon.ico" type="image/x-icon" />
<link rel="manifest" href="%PUBLIC_URL%/dsfr/favicon/manifest.webmanifest" crossorigin="use-credentials" />
<link rel="stylesheet" href="%PUBLIC_URL%/dsfr/fonts/index.css" />
<link rel="apple-touch-icon" href="/dsfr/favicon/apple-touch-icon.png" />
<link rel="icon" href="/dsfr/favicon/favicon.svg" type="image/svg+xml" />
<link rel="shortcut icon" href="/dsfr/favicon/favicon.ico" type="image/x-icon" />
<link rel="manifest" href="/dsfr/favicon/manifest.webmanifest" crossorigin="use-credentials" />
<link rel="stylesheet" href="/dsfr/fonts/index.css" />

<!-- Meta tags generated by metatags.io -->
<!-- Primary Meta Tags -->
Expand All @@ -16,13 +16,13 @@
<meta property="og:type" content="website">
<meta property="og:title" content="react-dsfr components">
<meta property="og:description" content="@codegouvfr/react-dsfr components playground and showcase">
<meta property="og:image" content="%PUBLIC_URL%/repo-card.png">
<meta property="og:image" content="/repo-card.png">

<!-- Twitter Meta Tags -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="react-dsfr components">
<meta name="twitter:description" content="@codegouvfr/react-dsfr components playground and showcase">
<meta name="twitter:image" content="%PUBLIC_URL%/repo-card.png">
<meta name="twitter:image" content="/repo-card.png">

<style>
.sidebar-item[data-nodetype="document"] svg {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"prebuild-storybook": "yarn prestorybook"
},
"bin": {
"react-dsfr": "dist/bin/react-dsfr.js",
"copy-dsfr-to-public": "dist/bin/copy-dsfr-to-public.js",
"only-include-used-icons": "dist/bin/only-include-used-icons.js"
},
Expand Down
48 changes: 24 additions & 24 deletions scripts/build/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,30 +133,30 @@ import yargsParser from "yargs-parser";
break local_testing;
}

fs.writeFileSync(
pathJoin(distDirPath, "package.json"),
Buffer.from(
JSON.stringify(
(() => {
const packageJsonParsed = JSON.parse(
fs
.readFileSync(pathJoin(projectRootDirPath, "package.json"))
.toString("utf8")
);

return {
...packageJsonParsed,
"main": packageJsonParsed["main"].replace(/^dist\//, ""),
"types": packageJsonParsed["types"].replace(/^dist\//, ""),
"module": packageJsonParsed["module"].replace(/^dist\//, "")
};
})(),
null,
2
),
"utf8"
)
);
{
let modifiedPackageJsonContent = fs
.readFileSync(pathJoin(projectRootDirPath, "package.json"))
.toString("utf8");

modifiedPackageJsonContent = (() => {
const o = JSON.parse(modifiedPackageJsonContent);

delete o.files;

return JSON.stringify(o, null, 2);
})();

modifiedPackageJsonContent = modifiedPackageJsonContent
.replace(/"dist\//g, '"')
.replace(/"\.\/dist\//g, '"./')
.replace(/"!dist\//g, '"!')
.replace(/"!\.\/dist\//g, '"!./');

fs.writeFileSync(
pathJoin(distDirPath, "package.json"),
Buffer.from(modifiedPackageJsonContent, "utf8")
);
}

fs.cpSync(dsfrDirPath, pathJoin(distDirPath, "dsfr"), { "recursive": true });
fs.rmSync(dsfrDirPath, { "recursive": true });
Expand Down
5 changes: 3 additions & 2 deletions scripts/build/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { parseCss } from "./parseCss";
import { assert } from "tsafe/assert";
import { exclude } from "tsafe/exclude";
import type { Icon } from "../../src/bin/only-include-used-icons";
import { pathOfPatchedRawCssCodeForCompatWithRemixIconRelativeToDsfrDist } from "../../src/bin/only-include-used-icons";
import { PATH_OF_PATCHED_RAW_CSS_CODE_FOR_COMPAT_WITH_REMIXICON_RELATIVE_TO_DSFR } from "../../src/bin/only-include-used-icons";
import { sep } from "path";
import * as css from "css";

Expand Down Expand Up @@ -55,7 +55,8 @@ export function getPatchedRawCssCodeForCompatWithRemixIcon(params: { rawCssCode:

const back =
new Array(
pathOfPatchedRawCssCodeForCompatWithRemixIconRelativeToDsfrDist.split(sep).length - 1
PATH_OF_PATCHED_RAW_CSS_CODE_FOR_COMPAT_WITH_REMIXICON_RELATIVE_TO_DSFR.split(sep)
.length - 1
)
.fill("..")
.join("/") + "/";
Expand Down
4 changes: 3 additions & 1 deletion scripts/link-in-external-project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ if (testAppPaths.length === 0) {
process.exit(-1);
}

testAppPaths.forEach(testAppPath => execSync("yarn install", { "cwd": testAppPath }));
testAppPaths.forEach(testAppPath =>
execSync("yarn install --ignore-scripts", { "cwd": testAppPath })
);

console.log("=== Linking common dependencies ===");

Expand Down
24 changes: 10 additions & 14 deletions src/bin/copy-dsfr-to-public.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#!/usr/bin/env node

/**
* This script is ran with `npx copy-dsfr-to-public`
* This script is ran with `npx react-dsfr copy-dsfr-to-public`
* It takes one optional arguments (for NX monorepos):
* - `--projectDir <path>` to specify the project directory. Default to the current working directory.
* This can be used in monorepos to specify the react project directory.
*/

import { join as pathJoin, resolve as pathResolve, relative as pathRelative } from "path";
import { join as pathJoin, resolve as pathResolve } from "path";
import * as fs from "fs";
import { getProjectRoot } from "./tools/getProjectRoot";
import yargsParser from "yargs-parser";
Expand All @@ -17,8 +17,8 @@ import { transformCodebase } from "./tools/transformCodebase";
import { assert } from "tsafe/assert";
import { modifyHtmlHrefs } from "./tools/modifyHtmlHrefs";

(async () => {
const argv = yargsParser(process.argv.slice(2));
export async function main(args: string[]) {
const argv = yargsParser(args);

const projectDirPath: string = (() => {
read_from_argv: {
Expand Down Expand Up @@ -69,7 +69,7 @@ import { modifyHtmlHrefs } from "./tools/modifyHtmlHrefs";

const gouvFrDsfrVersion: string = JSON.parse(
fs.readFileSync(pathJoin(getProjectRoot(), "package.json")).toString("utf8")
)["dependencies"]["@gouvfr/dsfr"];
)["devDependencies"]["@gouvfr/dsfr"];

const versionFilePath = pathJoin(dsfrDirPath, "version.txt");

Expand All @@ -89,10 +89,6 @@ import { modifyHtmlHrefs } from "./tools/modifyHtmlHrefs";
break early_exit;
}

console.log(
`DSFR distribution in ${pathRelative(process.cwd(), dsfrDirPath)} is up to date.`
);

return;
}

Expand Down Expand Up @@ -170,10 +166,6 @@ import { modifyHtmlHrefs } from "./tools/modifyHtmlHrefs";
return href;
}

if (href.endsWith("icons.min.css")) {
return href;
}

const [urlWithoutQuery] = href.split("?");

return `${urlWithoutQuery}?v=${gouvFrDsfrVersion}`;
Expand All @@ -186,7 +178,7 @@ import { modifyHtmlHrefs } from "./tools/modifyHtmlHrefs";

fs.writeFileSync(htmlFilePath, Buffer.from(modifiedHtml, "utf8"));
}
})();
}

function readAssetsImportFromDsfrCss(params: { dsfrSourceCode: string }): string[] {
const { dsfrSourceCode } = params;
Expand Down Expand Up @@ -223,3 +215,7 @@ function getRepoIssueUrl() {

return `${reactDsfrRepoUrl}/issues`;
}

if (require.main === module) {
main(process.argv.slice(2));
}
26 changes: 17 additions & 9 deletions src/bin/only-include-used-icons.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env node

/**
* This script is ran with `npx only-include-used-icons`
* This script is ran with `npx react-dsfr include-used-icons`
* It scans your codebase to find which icons are used and only include those in the final build.
* Do do that it patches the node_modules/@codegouvfr/react-dsfr/dist/utility/icons/icons.css file
* and the public/dsfr/utility/icons/icons.css file (if applicable, not in Next.js for example).
Expand Down Expand Up @@ -232,6 +232,8 @@ async function getCommandContext(args: string[]): Promise<CommandContext> {
if (!(await existsAsync(dsfrDirPath_static))) {
return undefined;
}

return dsfrDirPath_static;
})();

const htmlFilePath = await (async () => {
Expand Down Expand Up @@ -275,6 +277,10 @@ async function getCommandContext(args: string[]): Promise<CommandContext> {
"dirPath": projectDirPath,
"returnedPathsType": "absolute",
"getDoCrawlInDir": async ({ relativeDirPath }) => {
if (relativeDirPath === "dist") {
return false;
}

if (pathBasename(relativeDirPath) === "node_modules") {
return false;
}
Expand Down Expand Up @@ -398,8 +404,8 @@ async function getCommandContext(args: string[]): Promise<CommandContext> {
};
}

async function main() {
const commandContext = await getCommandContext(process.argv.slice(2));
export async function main(args: string[]) {
const commandContext = await getCommandContext(args);

const log = commandContext.isSilent ? undefined : console.log;

Expand Down Expand Up @@ -470,7 +476,7 @@ async function main() {
);
}

log?.(`Found ${usedIconClassNames.length} used icons.`);
log?.(`Found usage of ${usedIconClassNames.length} different icons.`);

const usedIcons = usedIconClassNames.map(className => {
const icon = icons.find(({ prefix, iconId }) => `${prefix}${iconId}` === className);
Expand Down Expand Up @@ -501,7 +507,7 @@ async function main() {

await Promise.all(
[commandContext.dsfrDirPath, commandContext.spaParams?.dsfrDirPath_static]
.filter(dirPath => dirPath !== undefined)
.filter(exclude(undefined))
.map(async dsfrDirPath => {
const cssFilePath = pathJoin(dsfrDirPath, iconsMinCssRelativePath);

Expand All @@ -518,14 +524,15 @@ async function main() {
);

if (!hasChanged) {
log?.("No change since last run");
return;
}

await Promise.all([
(async function generateUsedRemixiconFiles() {
await Promise.all(
[commandContext.dsfrDirPath, commandContext.spaParams?.dsfrDirPath_static]
.filter(dirPath => dirPath !== undefined)
.filter(exclude(undefined))
.map(async dsfrDistDirPath => {
const remixiconDirPath = pathJoin(dsfrDistDirPath, "icons", "remixicon");

Expand Down Expand Up @@ -556,7 +563,8 @@ async function main() {

await Promise.all(
usedIcons
.filter(icon => icon.prefix === "fr-icon-")
.map(icon => (icon.prefix !== "fr-icon-" ? undefined : icon))
.filter(exclude(undefined))
.map(({ svgRelativePath }) =>
([commandContext.dsfrDirPath, dsfrDirPath_static] as const).map(
baseDirPath =>
Expand All @@ -580,7 +588,7 @@ async function main() {
const { modifiedHtml } = modifyHtmlHrefs({
"html": html,
"getModifiedHref": href => {
if (!href.endsWith(iconsMinCssRelativePath.replace(/\\/g, "/"))) {
if (!href.includes(iconsMinCssRelativePath.replace(/\\/g, "/"))) {
return href;
}

Expand Down Expand Up @@ -622,5 +630,5 @@ async function main() {
}

if (require.main === module) {
main();
main(process.argv.slice(2));
}
23 changes: 23 additions & 0 deletions src/bin/react-dsfr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const [, , commandName, ...args] = process.argv;

(async () => {
switch (commandName) {
case "include-used-icons":
{
const { main } = await import("./only-include-used-icons");

await main(args);
}
break;
case "copy-dsfr-to-public":
{
const { main } = await import("./copy-dsfr-to-public");

await main(args);
}
break;
default:
console.error(`Unknown command ${commandName}`);
process.exit(-1);
}
})();

0 comments on commit 913c43a

Please sign in to comment.