Agent Skillsgrowilabs/growi › vendor-styles-components

vendor-styles-components

GitHub

解决Turbopack限制,通过Vite预编译将第三方CSS内联为JS模块,实现组件级按需加载,避免全局样式污染。

apps/app/.claude/skills/vendor-styles-components/SKILL.md growilabs/growi

触发场景

需要引入第三方库的CSS样式 在Turbopack环境下处理Vendor CSS

安装

npx skills add growilabs/growi --skill vendor-styles-components -g -y
更多选项

非标准路径

npx skills add https://github.com/growilabs/growi/tree/master/apps/app/.claude/skills/vendor-styles-components -g -y

不安装直接使用

npx skills use growilabs/growi@vendor-styles-components

指定 Agent (Claude Code)

npx skills add growilabs/growi --skill vendor-styles-components -a claude-code -g -y

安装 repo 全部 skill

npx skills add growilabs/growi --all -g -y

预览 repo 内 skill

npx skills add growilabs/growi --list

SKILL.md

Frontmatter
{
    "name": "vendor-styles-components",
    "description": "Vendor CSS precompilation system for Turbopack compatibility. How to add third-party CSS to components without violating Pages Router global CSS restriction. Auto-invoked when working in apps\/app."
}

Vendor CSS Precompilation (apps/app)

Problem

Turbopack (Pages Router) strictly enforces: global CSS can only be imported from _app.page.tsx. Components cannot import 'package/style.css' directly — Turbopack rejects these at compile time.

Centralizing all vendor CSS in _app would degrade FCP for pages that don't need those styles.

Solution: Two-Track Vendor CSS System

Commons Track (globally shared CSS)

  • File: src/styles/vendor.scss
  • For: CSS needed on most pages (e.g., simplebar-react)
  • Mechanism: Compiled via vite.vendor-styles-commons.ts into src/styles/prebuilt/
  • Imported from: _app.page.tsx

Components Track (component-specific CSS)

  • For: CSS needed only by specific components
  • Mechanism: Vite precompiles *.vendor-styles.ts entry points into *.vendor-styles.prebuilt.ts using ?inline CSS import suffix
  • Output: Pure JS modules (no CSS imports) — Turbopack sees them as regular JS

How It Works

  1. Entry point (ComponentName.vendor-styles.ts): imports CSS via Vite ?inline suffix, which inlines CSS as a string
  2. Runtime injection: the entry point creates a <style> tag and appends CSS to document.head
  3. Vite prebuild (pre:styles-components Turborepo task): compiles entry points into *.vendor-styles.prebuilt.ts
  4. Component import: imports the .prebuilt.ts file instead of raw CSS

Entry Point Template

// @ts-nocheck -- Processed by Vite only; ?inline is a Vite-specific import suffix
import css from 'some-package/dist/style.css?inline';

const s = document.createElement('style');
s.textContent = css;
document.head.appendChild(s);

For multiple CSS sources in one component:

// @ts-nocheck
import css1 from 'package-a/style.css?inline';
import css2 from 'package-b/style.css?inline';

const s = document.createElement('style');
s.textContent = css1 + css2;
document.head.appendChild(s);

Current Entry Points

Entry Point CSS Sources Consuming Components
Renderer.vendor-styles.ts @growi/remark-lsx, @growi/remark-attachment-refs, katex renderer.tsx
GrowiEditor.vendor-styles.ts @growi/editor PageEditor, CommentEditor
HandsontableModal.vendor-styles.ts handsontable (non-full variant) HandsontableModal
DateRangePicker.vendor-styles.ts react-datepicker DateRangePicker
RevisionDiff.vendor-styles.ts diff2html RevisionDiff
DrawioViewerWithEditButton.vendor-styles.ts @growi/remark-drawio DrawioViewerWithEditButton
ImageCropModal.vendor-styles.ts react-image-crop ImageCropModal
Presentation.vendor-styles.ts @growi/presentation Presentation, Slides

Adding New Vendor CSS

  1. Create {ComponentName}.vendor-styles.ts next to the consuming component:
    // @ts-nocheck
    import css from 'new-package/dist/style.css?inline';
    const s = document.createElement('style');
    s.textContent = css;
    document.head.appendChild(s);
    
  2. In the component, replace import 'new-package/dist/style.css' with:
    import './ComponentName.vendor-styles.prebuilt';
    
  3. Run pnpm run pre:styles-components (or let Turborepo handle it during dev/build)
  4. The .prebuilt.js file is git-ignored and auto-generated

Decision guide: If the CSS is needed on nearly every page, add it to the commons track (vendor.scss) instead.

Font/Asset Handling

When vendor CSS references external assets (e.g., KaTeX @font-face with url(fonts/KaTeX_*.woff2)):

  • Vite emits asset files to src/assets/ during build
  • The moveAssetsToPublic plugin (in vite.vendor-styles-components.ts) relocates them to public/static/fonts/
  • URL references in prebuilt JS are rewritten from /assets/ to /static/fonts/
  • Fonts are served by the existing express.static(crowi.publicDir) middleware
  • Both public/static/fonts/ and src/**/*.vendor-styles.prebuilt.ts are git-ignored

Build Pipeline Integration

turbo.json tasks:
  pre:styles-components  →  build (dependency)
  dev:pre:styles-components  →  dev (dependency)

Inputs:  vite.vendor-styles-components.ts, src/**/*.vendor-styles.ts, package.json
Outputs: src/**/*.vendor-styles.prebuilt.ts, public/static/fonts/**

Important Caveats

  • SSR: CSS is injected via <style> tags at runtime — not available during SSR. Most consuming components use next/dynamic({ ssr: false }), so FOUC is not a practical concern
  • @ts-nocheck: Required because ?inline is a Vite-specific import suffix not understood by TypeScript
  • handsontable: Must use handsontable/dist/handsontable.css (non-full, non-minified). The "full" variant (handsontable.full.min.css) contains IE CSS hacks (*zoom:1, filter:alpha()) that Turbopack's CSS parser (lightningcss) cannot parse. The "full" variant also includes Pikaday which is unused.

版本历史

  • 0dc62d2 当前 2026-08-20 19:46

同 Skill 集合

.claude/skills/detect-flaky-ci/SKILL.md
.claude/skills/essential-test-design/SKILL.md
.claude/skills/essential-test-patterns/SKILL.md
.claude/skills/investigate-flaky-test/SKILL.md
.claude/skills/kiro-debug/SKILL.md
.claude/skills/kiro-discovery/SKILL.md
.claude/skills/kiro-impl/SKILL.md
.claude/skills/kiro-review/SKILL.md
.claude/skills/kiro-spec-batch/SKILL.md
.claude/skills/kiro-spec-cleanup/SKILL.md
.claude/skills/kiro-spec-design/SKILL.md
.claude/skills/kiro-spec-init/SKILL.md
.claude/skills/kiro-spec-quick/SKILL.md
.claude/skills/kiro-spec-requirements/SKILL.md
.claude/skills/kiro-spec-tasks/SKILL.md
.claude/skills/kiro-steering-custom/SKILL.md
.claude/skills/kiro-steering/SKILL.md
.claude/skills/kiro-validate-design/SKILL.md
.claude/skills/kiro-validate-gap/SKILL.md
.claude/skills/kiro-validate-impl/SKILL.md
.claude/skills/kiro-verify-completion/SKILL.md
.claude/skills/mongoose-to-prisma/SKILL.md
apps/app/.claude/skills/app-architecture/SKILL.md
apps/app/.claude/skills/app-commands/SKILL.md
apps/app/.claude/skills/app-specific-patterns/SKILL.md
apps/app/.claude/skills/build-optimization/SKILL.md
apps/app/.claude/skills/next-express-route-consistency/SKILL.md
.claude/skills/kiro-spec-status/SKILL.md
.claude/skills/suggest-path-evaluator/SKILL.md
apps/app/.claude/skills/esm-merge-coverage/SKILL.md

元信息

文件数
0
版本
b2fbe5b
Hash
5e27fd27
收录时间
2026-08-20 19:46

首页 - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-09-21 16:50
浙ICP备14020137号-1