Skip to content

Commit 8b2b247

Browse files
committed
Only copy required files to public
1 parent a4fd44f commit 8b2b247

File tree

3 files changed

+184
-7
lines changed

3 files changed

+184
-7
lines changed

src/bin/copy-dsfr-to-public.ts

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import { getProjectRoot } from "./tools/getProjectRoot";
1717
import yargsParser from "yargs-parser";
1818
import { getAbsoluteAndInOsFormatPath } from "./tools/getAbsoluteAndInOsFormatPath";
1919
import { readPublicDirPath } from "./readPublicDirPath";
20+
import { transformCodebase } from "./tools/transformCodebase";
21+
import { assert } from "tsafe/assert";
2022

2123
(async () => {
2224
const argv = yargsParser(process.argv.slice(2));
@@ -73,7 +75,7 @@ import { readPublicDirPath } from "./readPublicDirPath";
7375

7476
fs.writeFileSync(pathJoin(dsfrDirPath, ".gitignore"), Buffer.from("*", "utf8"));
7577

76-
(function callee(depth: number) {
78+
const dsfrDistNodeModulesDirPath = (function dsfrDistNodeModulesDirPath(depth: number): string {
7779
const parentProjectDirPath = pathResolve(
7880
pathJoin(...[projectDirPath, ...new Array(depth).fill("..")])
7981
);
@@ -93,17 +95,73 @@ import { readPublicDirPath } from "./readPublicDirPath";
9395
process.exit(-1);
9496
}
9597

96-
callee(depth + 1);
97-
98-
return;
98+
return dsfrDistNodeModulesDirPath(depth + 1);
9999
}
100100

101-
fs.cpSync(dsfrDirPathInNodeModules, dsfrDirPath, {
102-
"recursive": true
103-
});
101+
return dsfrDirPathInNodeModules;
104102
})(0);
103+
104+
{
105+
const dsfrMinCssFileRelativePath = "dsfr.min.css";
106+
107+
const usedAssetsRelativeFilePaths = new Set(
108+
readAssetsImportFromDsfrCss({
109+
"dsfrSourceCode": fs
110+
.readFileSync(pathJoin(dsfrDistNodeModulesDirPath, dsfrMinCssFileRelativePath))
111+
.toString("utf8")
112+
})
113+
);
114+
115+
const fileToKeepRelativePaths = new Set([
116+
pathJoin("favicon", "apple-touch-icon.png"),
117+
pathJoin("favicon", "favicon.svg"),
118+
pathJoin("favicon", "favicon.ico"),
119+
pathJoin("favicon", "manifest.webmanifest"),
120+
pathJoin("utility", "icons", "icons.min.css"),
121+
dsfrMinCssFileRelativePath
122+
]);
123+
124+
transformCodebase({
125+
"srcDirPath": dsfrDistNodeModulesDirPath,
126+
"destDirPath": dsfrDirPath,
127+
"transformSourceCode": ({ fileRelativePath, sourceCode }) => {
128+
if (
129+
fileToKeepRelativePaths.has(fileRelativePath) ||
130+
usedAssetsRelativeFilePaths.has(fileRelativePath)
131+
) {
132+
return { "modifiedSourceCode": sourceCode };
133+
}
134+
}
135+
});
136+
}
105137
})();
106138

139+
function readAssetsImportFromDsfrCss(params: { dsfrSourceCode: string }): string[] {
140+
const { dsfrSourceCode } = params;
141+
142+
const fileRelativePaths = [/url\("([^"]+)"\)/g, /url\('([^']+)'\)/g, /url\(([^)]+)\)/g]
143+
.map(regex => {
144+
const fileRelativePaths: string[] = [];
145+
146+
dsfrSourceCode.replace(regex, (...[, relativeFilePath]) => {
147+
if (relativeFilePath.startsWith("data:")) {
148+
return "";
149+
}
150+
151+
fileRelativePaths.push(relativeFilePath);
152+
153+
return "";
154+
});
155+
156+
return fileRelativePaths;
157+
})
158+
.flat();
159+
160+
assert(fileRelativePaths.length !== 0);
161+
162+
return fileRelativePaths;
163+
}
164+
107165
function getRepoIssueUrl() {
108166
const reactDsfrRepoUrl = JSON.parse(
109167
fs.readFileSync(pathJoin(getProjectRoot(), "package.json")).toString("utf8")

src/bin/tools/crawlSync.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import * as fs from "fs";
2+
import { join as pathJoin, relative as pathRelative } from "path";
3+
4+
const crawlSyncRec = (dirPath: string, filePaths: string[]) => {
5+
for (const basename of fs.readdirSync(dirPath)) {
6+
const fileOrDirPath = pathJoin(dirPath, basename);
7+
8+
if (fs.lstatSync(fileOrDirPath).isDirectory()) {
9+
crawlSyncRec(fileOrDirPath, filePaths);
10+
11+
continue;
12+
}
13+
14+
filePaths.push(fileOrDirPath);
15+
}
16+
};
17+
18+
/** List all files in a given directory return paths relative to the dir_path */
19+
export function crawlSync(params: {
20+
dirPath: string;
21+
returnedPathsType: "absolute" | "relative to dirPath";
22+
}): string[] {
23+
const { dirPath, returnedPathsType } = params;
24+
25+
const filePaths: string[] = [];
26+
27+
crawlSyncRec(dirPath, filePaths);
28+
29+
switch (returnedPathsType) {
30+
case "absolute":
31+
return filePaths;
32+
case "relative to dirPath":
33+
return filePaths.map(filePath => pathRelative(dirPath, filePath));
34+
}
35+
}

src/bin/tools/transformCodebase.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import * as fs from "fs";
2+
import * as path from "path";
3+
import { crawlSync } from "./crawlSync";
4+
5+
type TransformSourceCode = (params: {
6+
sourceCode: Buffer;
7+
filePath: string;
8+
fileRelativePath: string;
9+
}) =>
10+
| {
11+
modifiedSourceCode: Buffer;
12+
newFileName?: string;
13+
}
14+
| undefined;
15+
16+
/**
17+
* Apply a transformation function to every file of directory
18+
* If source and destination are the same this function can be used to apply the transformation in place
19+
* like filtering out some files or modifying them.
20+
* */
21+
export function transformCodebase(params: {
22+
srcDirPath: string;
23+
destDirPath: string;
24+
transformSourceCode?: TransformSourceCode;
25+
}) {
26+
const { srcDirPath, transformSourceCode } = params;
27+
28+
const isTargetSameAsSource = path.relative(srcDirPath, params.destDirPath) === "";
29+
30+
const destDirPath = isTargetSameAsSource
31+
? path.join(srcDirPath, "..", "tmp_xOsPdkPsTdzPs34sOkHs")
32+
: params.destDirPath;
33+
34+
fs.mkdirSync(destDirPath, {
35+
recursive: true
36+
});
37+
38+
for (const fileRelativePath of crawlSync({
39+
dirPath: srcDirPath,
40+
returnedPathsType: "relative to dirPath"
41+
})) {
42+
const filePath = path.join(srcDirPath, fileRelativePath);
43+
const destFilePath = path.join(destDirPath, fileRelativePath);
44+
45+
// NOTE: Optimization, if we don't need to transform the file, just copy
46+
// it using the lower level implementation.
47+
if (transformSourceCode === undefined) {
48+
fs.mkdirSync(path.dirname(destFilePath), {
49+
recursive: true
50+
});
51+
52+
fs.copyFileSync(filePath, destFilePath);
53+
54+
continue;
55+
}
56+
57+
const transformSourceCodeResult = transformSourceCode({
58+
sourceCode: fs.readFileSync(filePath),
59+
filePath,
60+
fileRelativePath
61+
});
62+
63+
if (transformSourceCodeResult === undefined) {
64+
continue;
65+
}
66+
67+
fs.mkdirSync(path.dirname(destFilePath), {
68+
recursive: true
69+
});
70+
71+
const { newFileName, modifiedSourceCode } = transformSourceCodeResult;
72+
73+
fs.writeFileSync(
74+
path.join(path.dirname(destFilePath), newFileName ?? path.basename(destFilePath)),
75+
modifiedSourceCode
76+
);
77+
}
78+
79+
if (isTargetSameAsSource) {
80+
fs.rmSync(srcDirPath, { recursive: true });
81+
82+
fs.renameSync(destDirPath, srcDirPath);
83+
}
84+
}

0 commit comments

Comments
 (0)