@zealakit/css-doctor-next 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +120 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +120 -36
- package/dist/index.js.map +1 -1
- package/package.json +24 -2
package/dist/index.js
CHANGED
|
@@ -360,7 +360,10 @@ var CssDoctorWebpackPlugin = class {
|
|
|
360
360
|
pageUsage[page.name] = classes;
|
|
361
361
|
pageUsageCounts[page.name] = classes.length;
|
|
362
362
|
}
|
|
363
|
-
const
|
|
363
|
+
const hasPageClasses = pagesResult.pages.some(
|
|
364
|
+
(page) => page.classes.size > 0
|
|
365
|
+
);
|
|
366
|
+
const pageCoverageApplied = this.pageCoverage.enabled && hasPageClasses;
|
|
364
367
|
const diagnostics = {
|
|
365
368
|
plugin: "css-doctor-next",
|
|
366
369
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -449,7 +452,7 @@ var CssDoctorWebpackPlugin = class {
|
|
|
449
452
|
cssContent: originalCss,
|
|
450
453
|
pageUsage,
|
|
451
454
|
pageCoverage: {
|
|
452
|
-
enabled:
|
|
455
|
+
enabled: pageCoverageApplied,
|
|
453
456
|
minPageRatio: this.pageCoverage.minPageRatio,
|
|
454
457
|
forceCommon: this.pageCoverage.forceCommon
|
|
455
458
|
},
|
|
@@ -709,6 +712,7 @@ async function collectPages(compilation, directPageUsage) {
|
|
|
709
712
|
const pageEntries = [];
|
|
710
713
|
const sharedEntries = [];
|
|
711
714
|
const fallbackEntries = [];
|
|
715
|
+
const loaderFallbackEntries = [];
|
|
712
716
|
for (const entry of entries) {
|
|
713
717
|
const name = entryName(entry);
|
|
714
718
|
if (!name) {
|
|
@@ -725,12 +729,19 @@ async function collectPages(compilation, directPageUsage) {
|
|
|
725
729
|
name: routeNameForEntry(name) ?? name,
|
|
726
730
|
sourceName: name
|
|
727
731
|
});
|
|
732
|
+
} else {
|
|
733
|
+
loaderFallbackEntries.push({
|
|
734
|
+
entry,
|
|
735
|
+
name: routeNameForEntry(name) ?? name,
|
|
736
|
+
sourceName: name
|
|
737
|
+
});
|
|
728
738
|
}
|
|
729
739
|
}
|
|
730
740
|
const selectedPages = pageEntries.length > 0 ? pageEntries : fallbackEntries;
|
|
731
741
|
const direct = directPageUsage ? Object.keys(directPageUsage).length > 0 : false;
|
|
732
742
|
const pages = /* @__PURE__ */ new Map();
|
|
733
743
|
const pagesByCss = /* @__PURE__ */ new Map();
|
|
744
|
+
const projectRoot = compilation.compiler?.context ?? process.cwd();
|
|
734
745
|
if (direct && directPageUsage) {
|
|
735
746
|
for (const [rawName, classes] of Object.entries(directPageUsage)) {
|
|
736
747
|
const name = rawName.trim();
|
|
@@ -744,10 +755,27 @@ async function collectPages(compilation, directPageUsage) {
|
|
|
744
755
|
jsFiles: /* @__PURE__ */ new Set()
|
|
745
756
|
});
|
|
746
757
|
}
|
|
758
|
+
attachEntryAssetsToPages(pages, selectedPages);
|
|
759
|
+
const orphanPages = [...pages.values()].filter(
|
|
760
|
+
(page) => page.jsFiles.size === 0
|
|
761
|
+
);
|
|
762
|
+
if (orphanPages.length > 0) {
|
|
763
|
+
const loaderEntries = selectedPages.length > 0 ? selectedPages : loaderFallbackEntries;
|
|
764
|
+
const fallbackJs = /* @__PURE__ */ new Set();
|
|
765
|
+
for (const { entry } of loaderEntries) {
|
|
766
|
+
for (const jsFile of collectEntryJsFiles(entry)) {
|
|
767
|
+
fallbackJs.add(jsFile);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
for (const page of orphanPages) {
|
|
771
|
+
for (const jsFile of fallbackJs) {
|
|
772
|
+
page.jsFiles.add(jsFile);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
747
776
|
} else {
|
|
748
777
|
const sourceCache = /* @__PURE__ */ new Map();
|
|
749
778
|
const sharedClasses = /* @__PURE__ */ new Set();
|
|
750
|
-
const projectRoot = process.cwd();
|
|
751
779
|
for (const entry of sharedEntries) {
|
|
752
780
|
for (const className of await collectEntryClasses(
|
|
753
781
|
compilation,
|
|
@@ -800,19 +828,10 @@ async function collectPages(compilation, directPageUsage) {
|
|
|
800
828
|
const targetPages = [...pages.keys()];
|
|
801
829
|
for (const { entry, name } of selectedPages) {
|
|
802
830
|
const cssFiles = collectEntryCssFiles(entry);
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
directPage.cssFiles.add(cssFile);
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
} else {
|
|
811
|
-
const page = pages.get(name);
|
|
812
|
-
if (page) {
|
|
813
|
-
for (const cssFile of cssFiles) {
|
|
814
|
-
page.cssFiles.add(cssFile);
|
|
815
|
-
}
|
|
831
|
+
const page = findPageForEntry(pages, name);
|
|
832
|
+
if (page) {
|
|
833
|
+
for (const cssFile of cssFiles) {
|
|
834
|
+
page.cssFiles.add(cssFile);
|
|
816
835
|
}
|
|
817
836
|
}
|
|
818
837
|
}
|
|
@@ -837,18 +856,46 @@ async function collectPages(compilation, directPageUsage) {
|
|
|
837
856
|
pagesByCss
|
|
838
857
|
};
|
|
839
858
|
}
|
|
859
|
+
function attachEntryAssetsToPages(pages, selectedPages) {
|
|
860
|
+
for (const { entry, name } of selectedPages) {
|
|
861
|
+
const page = findPageForEntry(pages, name);
|
|
862
|
+
if (!page) {
|
|
863
|
+
continue;
|
|
864
|
+
}
|
|
865
|
+
for (const jsFile of collectEntryJsFiles(entry)) {
|
|
866
|
+
page.jsFiles.add(jsFile);
|
|
867
|
+
}
|
|
868
|
+
for (const cssFile of collectEntryCssFiles(entry)) {
|
|
869
|
+
page.cssFiles.add(cssFile);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
function findPageForEntry(pages, entryNameValue) {
|
|
874
|
+
const direct = pages.get(entryNameValue);
|
|
875
|
+
if (direct) {
|
|
876
|
+
return direct;
|
|
877
|
+
}
|
|
878
|
+
const normalized = normalizeSlashes(entryNameValue).replace(/^\/+/, "");
|
|
879
|
+
const bare = normalized.replace(/^\//, "");
|
|
880
|
+
return pages.get(normalized) ?? pages.get(`/${bare}`) ?? pages.get(bare) ?? pages.get(bare.replace(/\//g, "-"));
|
|
881
|
+
}
|
|
840
882
|
async function collectPageSourceClasses(entryName2, projectRoot, sourceCache) {
|
|
841
883
|
const classes = /* @__PURE__ */ new Set();
|
|
842
884
|
const visited = /* @__PURE__ */ new Set();
|
|
843
885
|
const normalized = normalizeSlashes(entryName2);
|
|
886
|
+
const roots = projectSourceRoots(projectRoot);
|
|
844
887
|
const candidates = [];
|
|
845
888
|
if (normalized.startsWith("app/")) {
|
|
846
889
|
const path = normalized.slice(4);
|
|
847
890
|
if (path === "page" || path.endsWith("/page")) {
|
|
848
891
|
const pagePath = path === "page" ? "app/page" : `app/${path}`;
|
|
849
|
-
|
|
892
|
+
for (const root of roots) {
|
|
893
|
+
candidates.push(resolve2(root, pagePath));
|
|
894
|
+
}
|
|
850
895
|
if (path === "_not-found/page") {
|
|
851
|
-
|
|
896
|
+
for (const root of roots) {
|
|
897
|
+
candidates.push(resolve2(root, "app/not-found"));
|
|
898
|
+
}
|
|
852
899
|
}
|
|
853
900
|
const directories = path.split("/").slice(0, -1).filter(Boolean);
|
|
854
901
|
const layoutPaths = ["app"];
|
|
@@ -856,16 +903,24 @@ async function collectPageSourceClasses(entryName2, projectRoot, sourceCache) {
|
|
|
856
903
|
layoutPaths.push(`app/${directories.slice(0, index + 1).join("/")}`);
|
|
857
904
|
}
|
|
858
905
|
for (const layoutPath of layoutPaths) {
|
|
859
|
-
|
|
906
|
+
for (const root of roots) {
|
|
907
|
+
candidates.push(resolve2(root, `${layoutPath}/layout`));
|
|
908
|
+
}
|
|
860
909
|
}
|
|
861
910
|
} else {
|
|
862
|
-
|
|
911
|
+
for (const root of roots) {
|
|
912
|
+
candidates.push(resolve2(root, normalized));
|
|
913
|
+
}
|
|
863
914
|
}
|
|
864
915
|
} else if (normalized.startsWith("pages/")) {
|
|
865
|
-
|
|
866
|
-
|
|
916
|
+
for (const root of roots) {
|
|
917
|
+
candidates.push(resolve2(root, normalized));
|
|
918
|
+
candidates.push(resolve2(root, "pages/_app"));
|
|
919
|
+
}
|
|
867
920
|
} else {
|
|
868
|
-
|
|
921
|
+
for (const root of roots) {
|
|
922
|
+
candidates.push(resolve2(root, normalized));
|
|
923
|
+
}
|
|
869
924
|
}
|
|
870
925
|
for (const candidate of candidates) {
|
|
871
926
|
const file = findSourceFile(candidate);
|
|
@@ -878,13 +933,23 @@ async function collectPageSourceClasses(entryName2, projectRoot, sourceCache) {
|
|
|
878
933
|
async function collectNameSourceClasses(entryName2, projectRoot, sourceCache) {
|
|
879
934
|
const classes = /* @__PURE__ */ new Set();
|
|
880
935
|
const visited = /* @__PURE__ */ new Set();
|
|
881
|
-
const
|
|
882
|
-
const
|
|
883
|
-
|
|
884
|
-
|
|
936
|
+
const relative = normalizeSlashes(entryName2);
|
|
937
|
+
for (const root of projectSourceRoots(projectRoot)) {
|
|
938
|
+
const file = findSourceFile(resolve2(root, relative));
|
|
939
|
+
if (file) {
|
|
940
|
+
await scanSourceFile(file, classes, projectRoot, sourceCache, visited);
|
|
941
|
+
}
|
|
885
942
|
}
|
|
886
943
|
return classes;
|
|
887
944
|
}
|
|
945
|
+
function projectSourceRoots(projectRoot) {
|
|
946
|
+
const roots = [projectRoot];
|
|
947
|
+
const srcRoot = resolve2(projectRoot, "src");
|
|
948
|
+
if (srcRoot !== projectRoot && existsSync2(srcRoot)) {
|
|
949
|
+
roots.push(srcRoot);
|
|
950
|
+
}
|
|
951
|
+
return roots;
|
|
952
|
+
}
|
|
888
953
|
async function scanSourceFile(filePath, classes, projectRoot, sourceCache, visited) {
|
|
889
954
|
const absolutePath = resolve2(filePath);
|
|
890
955
|
if (visited.has(absolutePath)) {
|
|
@@ -968,18 +1033,28 @@ function extractImportSpecifiers(source) {
|
|
|
968
1033
|
return [...specifiers];
|
|
969
1034
|
}
|
|
970
1035
|
function resolveImportSpecifier(specifier, fromFile, projectRoot) {
|
|
971
|
-
let basePath;
|
|
972
1036
|
if (specifier.startsWith("@/")) {
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
1037
|
+
const relative = specifier.slice(2);
|
|
1038
|
+
for (const root of projectSourceRoots(projectRoot)) {
|
|
1039
|
+
const basePath = resolve2(root, relative);
|
|
1040
|
+
if (isStyleFile(basePath)) {
|
|
1041
|
+
return null;
|
|
1042
|
+
}
|
|
1043
|
+
const found = findSourceFile(basePath);
|
|
1044
|
+
if (found) {
|
|
1045
|
+
return found;
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
977
1048
|
return null;
|
|
978
1049
|
}
|
|
979
|
-
if (
|
|
980
|
-
|
|
1050
|
+
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
1051
|
+
const basePath = resolve2(dirname2(fromFile), specifier);
|
|
1052
|
+
if (isStyleFile(basePath)) {
|
|
1053
|
+
return null;
|
|
1054
|
+
}
|
|
1055
|
+
return findSourceFile(basePath);
|
|
981
1056
|
}
|
|
982
|
-
return
|
|
1057
|
+
return null;
|
|
983
1058
|
}
|
|
984
1059
|
async function collectEntryClasses(compilation, entry, sourceCache) {
|
|
985
1060
|
const classes = /* @__PURE__ */ new Set();
|
|
@@ -1148,13 +1223,22 @@ function scanClasses(source, classes) {
|
|
|
1148
1223
|
continue;
|
|
1149
1224
|
}
|
|
1150
1225
|
for (const token of value.split(/\s+/)) {
|
|
1151
|
-
if (
|
|
1226
|
+
if (isClassToken(token)) {
|
|
1152
1227
|
classes.add(token.toLowerCase());
|
|
1153
1228
|
}
|
|
1154
1229
|
}
|
|
1155
1230
|
}
|
|
1156
1231
|
}
|
|
1157
1232
|
}
|
|
1233
|
+
function isClassToken(token) {
|
|
1234
|
+
if (!token || token.length > 256) {
|
|
1235
|
+
return false;
|
|
1236
|
+
}
|
|
1237
|
+
if (/[`${}]/.test(token)) {
|
|
1238
|
+
return false;
|
|
1239
|
+
}
|
|
1240
|
+
return /[A-Za-z_]/.test(token);
|
|
1241
|
+
}
|
|
1158
1242
|
function addCssOwner(pagesByCss, cssFile, page) {
|
|
1159
1243
|
const owners = pagesByCss.get(cssFile) ?? /* @__PURE__ */ new Set();
|
|
1160
1244
|
owners.add(page);
|