fix(workspace): make pnpm monorepo actually verify clean
After the apps/packages split, several setup gaps surfaced when running the full lint/typecheck/test/build chain: Build & install - .npmrc: switch to npmmirror + raise fetch-timeout (next/swc tarballs were timing out against npmjs.org) - pnpm-workspace.yaml: approve esbuild build script (tsup needs it) - pnpm-lock.yaml: regenerated for the new workspace layout - .gitignore: ignore apps/*/.next, apps/*/out, packages/*/dist (the root-only globs no longer covered post-split) Script ordering — playground typecheck/dev/build read types from the library's dist/, so the lib must build first: - root package.json: prepend build:lib to dev/typecheck/build:playground - root package.json: add start/preview scripts for previewing prod build TypeScript config - tsconfig.base.json: drop incremental: true (broke tsup's DTS step; TS5074 — needs tsBuildInfoFile when emitted from tsup) - apps/playground/tsconfig.json: re-add incremental locally (Next uses it) Library typecheck fixes — needed to make tsup's DTS step pass: - utils.ts, core/binary.ts: drop Uint8Array<ArrayBuffer> generic (5.7+ syntax; we keep ^5 in deps so the source must compile on older TS too) - XlsxPreview.tsx: cast bytes.buffer as ArrayBuffer (now ArrayBufferLike by default; exceljs's .xlsx.load expects ArrayBuffer) - icons.tsx: wrap rest-children in Children.toArray() so multi-path icons (EyeIcon, Code2Icon, …) get auto-keys — was throwing the 'unique key prop' warning on every page load - vitest.setup.ts → src/__tests__/setup.ts + update vitest.config.ts: the setup file was outside rootDir 'src', breaking tsc --noEmit; moving it under src/__tests__ keeps tsup's entry filter happy Cleanup - apps/playground/src/lib/shiki.ts: orphan from the split (no importers; the real shiki module lives in packages/file-preview/src/shiki.ts) After all this: lint / typecheck / test / build:lib / build:playground all green. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -16,9 +16,15 @@ node_modules
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
apps/*/.next/
|
||||
apps/*/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
apps/*/build
|
||||
|
||||
# package builds
|
||||
packages/*/dist/
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
registry=https://registry.npmmirror.com
|
||||
fetch-timeout=600000
|
||||
fetch-retries=5
|
||||
fetch-retry-mintimeout=20000
|
||||
fetch-retry-maxtimeout=120000
|
||||
network-concurrency=4
|
||||
@@ -1,164 +0,0 @@
|
||||
/**
|
||||
* Shiki highlighter — lazy loading via main entry
|
||||
*
|
||||
* The `shiki` main entry automatically code-splits each language and theme
|
||||
* into separate async chunks. Only the ones actually used are loaded.
|
||||
*
|
||||
* Loading sequence for first code preview:
|
||||
* 0KB (React.lazy) → core + JS engine + 1 lang + 2 themes ≈ 49KB gzip
|
||||
*
|
||||
* Turbopack/webpack automatically splits each @shikijs/langs/* and
|
||||
* @shikijs/themes/* into separate chunks.
|
||||
*/
|
||||
|
||||
import { codeToHtml as shikiCodeToHtml } from "shiki";
|
||||
import type { ShikiTransformer } from "shiki";
|
||||
|
||||
// Re-export for convenience
|
||||
export { shikiCodeToHtml };
|
||||
|
||||
/**
|
||||
* Highlight code with dual theme support (light/dark CSS variables)
|
||||
*
|
||||
* This is a wrapper around shiki's codeToHtml that:
|
||||
* - Uses github-light/github-dark dual themes
|
||||
* - Outputs CSS variables (defaultColor: false) for zero-cost theme switching
|
||||
* - Adds line numbers via transformer
|
||||
*/
|
||||
export async function highlightCode(
|
||||
content: string,
|
||||
language: string
|
||||
): Promise<string> {
|
||||
return shikiCodeToHtml(content, {
|
||||
lang: language,
|
||||
themes: {
|
||||
light: "github-light",
|
||||
dark: "github-dark",
|
||||
},
|
||||
defaultColor: false,
|
||||
transformers: [transformerLineNumbers()],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Map file extension → Shiki language ID
|
||||
*/
|
||||
export function getShikiLanguage(fileName: string): string {
|
||||
const ext = fileName.toLowerCase().split(".").pop() || "";
|
||||
const baseName = fileName.split("/").pop() || "";
|
||||
|
||||
const extMap: Record<string, string> = {
|
||||
// Web
|
||||
js: "javascript",
|
||||
mjs: "javascript",
|
||||
cjs: "javascript",
|
||||
jsx: "jsx",
|
||||
ts: "typescript",
|
||||
tsx: "tsx",
|
||||
html: "html",
|
||||
htm: "html",
|
||||
css: "css",
|
||||
scss: "scss",
|
||||
less: "less",
|
||||
vue: "vue",
|
||||
svelte: "svelte",
|
||||
// Scripting
|
||||
py: "python",
|
||||
pyw: "python",
|
||||
rb: "ruby",
|
||||
php: "php",
|
||||
pl: "perl",
|
||||
pm: "perl",
|
||||
lua: "lua",
|
||||
r: "r",
|
||||
// Systems
|
||||
java: "java",
|
||||
c: "c",
|
||||
h: "c",
|
||||
cpp: "cpp",
|
||||
cc: "cpp",
|
||||
cxx: "cpp",
|
||||
hpp: "cpp",
|
||||
cs: "csharp",
|
||||
go: "go",
|
||||
rs: "rust",
|
||||
swift: "swift",
|
||||
kt: "kotlin",
|
||||
kts: "kotlin",
|
||||
scala: "scala",
|
||||
dart: "dart",
|
||||
// Shell
|
||||
sh: "bash",
|
||||
bash: "bash",
|
||||
zsh: "bash",
|
||||
ps1: "powershell",
|
||||
bat: "bat",
|
||||
cmd: "bat",
|
||||
// Data / Config
|
||||
json: "json",
|
||||
yml: "yaml",
|
||||
yaml: "yaml",
|
||||
toml: "toml",
|
||||
ini: "ini",
|
||||
cfg: "ini",
|
||||
conf: "ini",
|
||||
env: "ini",
|
||||
sql: "sql",
|
||||
graphql: "graphql",
|
||||
gql: "graphql",
|
||||
xml: "xml",
|
||||
svg: "xml",
|
||||
// DevOps
|
||||
dockerfile: "dockerfile",
|
||||
makefile: "makefile",
|
||||
nginx: "nginx",
|
||||
diff: "diff",
|
||||
patch: "diff",
|
||||
// Docs
|
||||
md: "markdown",
|
||||
mdx: "mdx",
|
||||
tex: "latex",
|
||||
adoc: "asciidoc",
|
||||
// Functional / Other
|
||||
ex: "elixir",
|
||||
exs: "elixir",
|
||||
clj: "clojure",
|
||||
cljs: "clojure",
|
||||
erl: "erlang",
|
||||
hs: "haskell",
|
||||
m: "matlab",
|
||||
vim: "vim",
|
||||
coffee: "coffeescript",
|
||||
wasm: "wasm",
|
||||
objectivec: "objectivec",
|
||||
objectivecpp: "objectivec",
|
||||
};
|
||||
|
||||
if (extMap[ext]) return extMap[ext];
|
||||
|
||||
// Check base filename (case-insensitive)
|
||||
const lowerBase = baseName.toLowerCase();
|
||||
if (lowerBase === "dockerfile") return "dockerfile";
|
||||
if (lowerBase === "makefile" || lowerBase === "gnumakefile") return "makefile";
|
||||
if (lowerBase === "gemfile") return "ruby";
|
||||
if (lowerBase === "rakefile") return "ruby";
|
||||
if (lowerBase === ".gitignore" || lowerBase === ".env") return "ini";
|
||||
if (lowerBase === ".eslintrc" || lowerBase === ".prettierrc") return "json";
|
||||
if (lowerBase === "vagrantfile") return "ruby";
|
||||
|
||||
return "text";
|
||||
}
|
||||
|
||||
/**
|
||||
* Transformer: add data-line attribute to each line for CSS line numbers
|
||||
*/
|
||||
export function transformerLineNumbers(): ShikiTransformer {
|
||||
return {
|
||||
name: "line-numbers",
|
||||
line(lineProps, line) {
|
||||
// lineProps is a hast element; properties are in .properties
|
||||
if (!lineProps.properties) lineProps.properties = {};
|
||||
lineProps.properties["data-line"] = String(line);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"incremental": true,
|
||||
"plugins": [{ "name": "next" }],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
|
||||
+5
-3
@@ -9,12 +9,14 @@
|
||||
"pnpm": ">=11.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "pnpm --filter @filevista/playground dev",
|
||||
"dev": "pnpm --filter @filevista/file-preview build && pnpm --filter @filevista/playground dev",
|
||||
"build": "pnpm --filter @filevista/file-preview build && pnpm --filter @filevista/playground build",
|
||||
"build:lib": "pnpm --filter @filevista/file-preview build",
|
||||
"build:playground": "pnpm --filter @filevista/playground build",
|
||||
"build:playground": "pnpm --filter @filevista/file-preview build && pnpm --filter @filevista/playground build",
|
||||
"start": "pnpm --filter @filevista/playground start",
|
||||
"preview": "pnpm run build && pnpm run start",
|
||||
"lint": "pnpm -r run lint",
|
||||
"typecheck": "pnpm -r run typecheck",
|
||||
"typecheck": "pnpm --filter @filevista/file-preview build && pnpm -r run typecheck",
|
||||
"test": "pnpm --filter @filevista/file-preview test",
|
||||
"check": "pnpm run lint && pnpm run typecheck && pnpm run test && pnpm run build"
|
||||
},
|
||||
|
||||
@@ -371,7 +371,7 @@ async function parseXlsx(
|
||||
// exceljs's typings ask for Node's Buffer, but its browser bundle
|
||||
// accepts any ArrayBufferView at runtime. Pass the underlying ArrayBuffer
|
||||
// to satisfy both layers without a structured cast.
|
||||
await workbook.xlsx.load(bytes.buffer);
|
||||
await workbook.xlsx.load(bytes.buffer as ArrayBuffer);
|
||||
|
||||
const sheets: SheetData[] = [];
|
||||
const isFast = mode === "fast";
|
||||
|
||||
@@ -29,7 +29,7 @@ export async function readBinaryPreviewAsArrayBuffer({
|
||||
|
||||
export async function readBinaryPreviewAsUint8Array(
|
||||
input: BinaryPreviewInput
|
||||
): Promise<Uint8Array<ArrayBuffer>> {
|
||||
): Promise<Uint8Array> {
|
||||
const buffer = await readBinaryPreviewAsArrayBuffer(input);
|
||||
return new Uint8Array(buffer);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* Consumers can override size via the `size` prop; color follows `currentColor`.
|
||||
*/
|
||||
|
||||
import { Children } from "react";
|
||||
|
||||
interface IconProps extends React.SVGProps<SVGSVGElement> {
|
||||
size?: number;
|
||||
}
|
||||
@@ -33,7 +35,7 @@ function icon(props: IconProps, ...children: React.ReactNode[]) {
|
||||
strokeLinejoin={defaults.strokeLinejoin}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
{Children.toArray(children)}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ export function generateId(): string {
|
||||
* Decode base64 string to Uint8Array.
|
||||
* Shared utility used by PDF, DOCX, DOC, PPTX, XLSX, EPUB, ZIP preview components.
|
||||
*/
|
||||
export function base64ToUint8Array(base64: string): Uint8Array<ArrayBuffer> {
|
||||
export function base64ToUint8Array(base64: string): Uint8Array {
|
||||
const binaryString = atob(base64);
|
||||
const bytes = new Uint8Array(binaryString.length);
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
|
||||
@@ -8,7 +8,7 @@ export default defineConfig({
|
||||
test: {
|
||||
environment: "node", // individual tests opt in to jsdom via `// @vitest-environment jsdom`
|
||||
globals: false,
|
||||
setupFiles: ["./vitest.setup.ts"],
|
||||
setupFiles: ["./src/__tests__/setup.ts"],
|
||||
include: [
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.test.tsx",
|
||||
|
||||
Generated
+9642
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@ allowBuilds:
|
||||
'@swc/core': true
|
||||
canvas: false
|
||||
es5-ext: true
|
||||
esbuild: true
|
||||
prisma: false
|
||||
sharp: true
|
||||
unrs-resolver: true
|
||||
|
||||
+1
-2
@@ -11,7 +11,6 @@
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"incremental": true
|
||||
"jsx": "react-jsx"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user