Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
7a299c6
refactor: migrate to unplugin
romhml Mar 7, 2025
fe79e26
chore: add vue playground
romhml Mar 8, 2025
9c89ce8
refactor: migrate collections and meta to vite
romhml Mar 8, 2025
4332689
refactor: refresh meta on hmr
romhml Mar 8, 2025
28cd55c
refactor: use api instead of virtual imports
romhml Mar 9, 2025
9397593
refactor: migrate component example logic to vite
romhml Mar 9, 2025
8011044
refactor: migrate library collections
romhml Mar 9, 2025
bbbc0b0
chore: up
romhml Mar 9, 2025
6c6c8cc
refactor: up
romhml Mar 11, 2025
4a21de6
Merge branch 'main' of github.com:romhml/compodium into refactor/vite…
romhml Mar 11, 2025
27c4830
Merge branch 'main' of github.com:romhml/compodium into refactor/vite…
romhml Mar 11, 2025
d7ebdbc
chore: up
romhml Mar 11, 2025
cfcf812
chore: up
romhml Mar 11, 2025
69ae634
fix: root component renderering
romhml Mar 11, 2025
084bc10
feat(vue): generate renderer entry point from main.ts
romhml Mar 11, 2025
86bf2ed
feat: create virtual module for preview component
romhml Mar 11, 2025
eef8d84
chore: cleanup dependencies
romhml Mar 11, 2025
a683bf3
chore: up
romhml Mar 11, 2025
381d3b8
chore: up
romhml Mar 11, 2025
0ccec3e
chore: up
romhml Mar 11, 2025
85eac57
feat(vue): inject script to add devtools tab
romhml Mar 11, 2025
4c6396b
chore: up
romhml Mar 11, 2025
d28341e
refactor: strip extendCompodiumMeta and improve resolutions
romhml Mar 11, 2025
ce89460
chore: up
romhml Mar 11, 2025
c74ba4b
refactor: example fetching api
romhml Mar 11, 2025
bbb90cb
refactor: iconify api
romhml Mar 11, 2025
4b08e2a
chore: up
romhml Mar 11, 2025
c659727
fix: use component real path in renderer import
romhml Mar 12, 2025
16da37b
refactor: ui colors customization
romhml Mar 12, 2025
00de27e
fix: hmr
romhml Mar 12, 2025
dba4ddb
chore: up
romhml Mar 12, 2025
09077fb
feat: add client side caching for devtools ui
romhml Mar 12, 2025
04172bc
fix: extendCompodiumMeta typing
romhml Mar 12, 2025
3521fa0
Merge branch 'main' of github.com:romhml/compodium into refactor/vite…
romhml Mar 12, 2025
4176342
fix: library detection for vue
romhml Mar 13, 2025
029625e
chore: up
romhml Mar 13, 2025
46ee40c
test: fix
romhml Mar 13, 2025
a1c174e
test: fix
romhml Mar 13, 2025
f9f26c9
fix: typechecks
romhml Mar 13, 2025
6f5720f
fix: tests
romhml Mar 13, 2025
761de7f
fix: tests
romhml Mar 13, 2025
d57f876
chore: up
romhml Mar 13, 2025
20c1a3b
chore: up
romhml Mar 13, 2025
65e93c6
feat: strip imports from examples in Nuxt
romhml Mar 15, 2025
fcd9034
chore: simplify table example
romhml Mar 15, 2025
050815c
chore: improve dev commands
romhml Mar 15, 2025
bf05cf8
chore: up
romhml Mar 15, 2025
ffc69f4
chore: forward devtools ws in dev mode
romhml Mar 15, 2025
ae6f88d
fix(devtools): missing props in example components
romhml Mar 15, 2025
e800904
chore: revert nuxt to 3.15
romhml Mar 15, 2025
9e414ba
chore: up
romhml Mar 15, 2025
21a6586
chore: revert nuxt/ui to 3.0.0-beta.3
romhml Mar 15, 2025
9e9e8d0
fix: example styles
romhml Mar 16, 2025
9b655ff
fix: only use tw theme and utilities in examples
romhml Mar 16, 2025
d0d61fe
chore: remove placeholder component
romhml Mar 16, 2025
be319b9
feat(devtools): maintain props on HMR if state has been touched
romhml Mar 16, 2025
85e4322
feat(examples): add example pattern
romhml Mar 16, 2025
86194e1
fix: up
romhml Mar 16, 2025
7cbfb12
fix: up
romhml Mar 16, 2025
42ebd5f
fix: up
romhml Mar 16, 2025
9f15b88
fix(meta): package files
romhml Mar 16, 2025
023e12b
chore: up
romhml Mar 16, 2025
0664c24
fix: workspace deps version specifier
romhml Mar 16, 2025
798cc04
fix: import resolution in virtual templates
romhml Mar 16, 2025
556ce1e
chore: up
romhml Mar 16, 2025
51c029f
chore: vue advertisement
romhml Mar 16, 2025
0341074
fix(vue): import errors in examples
romhml Mar 16, 2025
ec53e68
fix(devtools): reset dirty check on component change
romhml Mar 16, 2025
fdb1b93
fix: icon input
romhml Mar 17, 2025
bfd960e
chore: up
romhml Mar 17, 2025
5b338eb
fix(vue): remove imports from examples
romhml Mar 17, 2025
c53aca4
fix(devtools): add deepEq check for default props
romhml Mar 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ jobs:
run: pnpm test

- name: Publish
run: pnpx pkg-pr-new publish --no-template --pnpm './packages/nuxt' './packages/meta'
run: pnpx pkg-pr-new publish --no-template --pnpm './packages/*'
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
filter=@compodium/*
shamefully-hoist=true
strict-peer-dependencies=false
13 changes: 13 additions & 0 deletions build.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { BuildConfig } from 'unbuild'

export default {
clean: true,
rollup: {
esbuild: {
target: 'esnext'
},
emitCJS: true,
cjsBridge: true
},
declaration: true
} satisfies BuildConfig
19 changes: 14 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,32 @@
"license": "MIT",
"type": "module",
"scripts": {
"dev:prepare": "pnpm -r dev:prepare",
"dev": "COMPODIUM_LOCAL=true nuxi dev playground",
"dev:prepare": "pnpm -r --color dev:prepare",
"dev": "COMPODIUM_DEVTOOLS_URL=http://localhost:4242 pnpm --color --parallel -r dev",
"dev:nuxt": "COMPODIUM_DEVTOOLS_URL=http://localhost:4242 pnpm --color --parallel --filter '!@compodium/playground-vue' dev",
"dev:vue": "COMPODIUM_DEVTOOLS_URL=http://localhost:4242 pnpm --color --parallel --filter '!@compodium/playground-nuxt' dev",
"lint": "eslint .",
"typecheck": "pnpm -r typecheck",
"test": "pnpm -r test",
"typecheck": "pnpm -r --color typecheck",
"test": "pnpm -r --color test",
"bump": "jiti ./scripts/bump.ts"
},
"devDependencies": {
"@nuxt/eslint-config": "^1.2.0",
"@nuxt/test-utils": "^3.17.2",
"@types/node": "^22.13.1",
"changelogen": "^0.6.1",
"eslint": "^9.22.0",
"typescript": "5.6.3",
"unbuild": "^3.5.0",
"vite": "^6.1.0",
"vitest": "^3.0.8"
},
"resolutions": {
"rollup": "4.35.0",
"typescript": "5.6.3",
"vue-tsc": "2.2.0"
"vue-tsc": "2.2.0",
"nuxt": "3.15.4",
"@nuxt/ui": "3.0.0-beta.3"
},
"packageManager": "[email protected]"
}
81 changes: 81 additions & 0 deletions packages/core/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# parcel-bundler cache (https://parceljs.org/)
.cache

# next.js build output
.next

# nuxt.js build output
.nuxt

# Nuxt generate
dist

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless

# IDE
.idea
3 changes: 3 additions & 0 deletions packages/core/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"eslint.experimental.useFlatConfig": true
}
11 changes: 11 additions & 0 deletions packages/core/build.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineBuildConfig } from 'unbuild'
import config from '../../build.config'

export default defineBuildConfig({
...config,
entries: [
'src/index',
{ builder: 'copy', input: './src/runtime', outDir: './dist/runtime' },
{ builder: 'copy', input: '../../', pattern: 'LICENSE.md|README.md' }
]
})
60 changes: 60 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"name": "@compodium/core",
"type": "module",
"version": "0.1.0-beta.5",
"description": "A plug and play component playground for Vue and Nuxt.",
"license": "MIT",
"repository": {
"url": "romhml/compodium",
"directory": "packages/core"
},
"keywords": [
"nuxt",
"components",
"documentation"
],
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
},
"./*": "./dist/*"
},
"main": "dist/index.cjs",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"dev:prepare": "unbuild",
"dev": "unbuild --watch",
"prepack": "unbuild && pnpm --filter devtools generate",
"typecheck": "tsc --noEmit"
},
"peerDependencies": {
"@nuxt/schema": ">=3",
"vite": ">=3",
"vue": ">=3"
},
"peerDependenciesMeta": {
"vite": {
"optional": true
}
},
"dependencies": {
"@compodium/examples": "workspace:^",
"@compodium/meta": "workspace:^",
"@vueuse/core": "^12.8.2",
"chokidar": "^4.0.3",
"hookable": "^5.5.3",
"pathe": "^2.0.3",
"scule": "^1.3.0",
"sirv": "^3.0.1",
"tinyglobby": "^0.2.12",
"ufo": "^1.5.4",
"unplugin": "^2.2.0",
"unplugin-ast": "^0.14.3",
"zod": "^3.24.2"
}
}
79 changes: 79 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { joinURL } from 'ufo'
import AST from 'unplugin-ast/vite'
import { RemoveWrapperFunction } from 'unplugin-ast/transformers'

import { libraryCollections as libraryCollectionsConfig } from '@compodium/examples'
import { collectionsPlugin } from './plugins/collections'
import { metaPlugin } from './plugins/meta'
import { examplePlugin } from './plugins/examples'
import { devtoolsPlugin } from './plugins/devtools'
import { colorsPlugin } from './plugins/colors'
import { iconifyPlugin } from './plugins/iconify'

import type { Collection, PluginConfig, PluginOptions } from './types'

export * from './types'

export const compodium = /* #__PURE__ */ (options: PluginOptions) => {
const exampleDir = {
path: joinURL(options.rootDir, options.dir, 'examples'),
pattern: '**/*.{vue,tsx}'
}

const componentDirs = options?.componentDirs.map((dir) => {
const componentDir = typeof dir === 'string' ? { path: dir } : dir
return {
pattern: '**/*.{vue,tsx}',
...componentDir,
ignore: (componentDir.ignore ?? []).concat(options.ignore ?? [])
}
}).filter(collection => !collection.path?.includes('node_modules/'))

const componentCollection: Collection = {
name: 'Components',
exampleDir,
dirs: componentDirs
}

const libraryCollections = options.includeLibraryCollections
? options.componentDirs.map((dir) => {
const path = typeof dir === 'string' ? dir : dir.path
const collection = libraryCollectionsConfig.find((c: any) => path.includes(`node_modules/${c.package}`))
if (collection) {
return {
...collection,
exampleDir: {
...typeof dir === 'string' ? {} : dir,
path: collection.exampleDir,
pattern: '**/*.{vue,tsx}'
},
dirs: [{
...typeof dir === 'string' ? {} : dir,
path,
pattern: '**/*.{vue,tsx}',
ignore: collection.ignore
}]
}
}
}).filter(c => !!c)
: []

const config: PluginConfig = {
...options,
libraryCollections,
componentCollection
}

return [
collectionsPlugin(config),
metaPlugin(config),
devtoolsPlugin(config),
examplePlugin(config),
iconifyPlugin(config),
colorsPlugin(config),
AST({
include: [/\.[jt]sx?$/, /\.vue$/],
transformer: [RemoveWrapperFunction(['extendCompodiumMeta'])]
})
]
}
94 changes: 94 additions & 0 deletions packages/core/src/plugins/collections.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import type { PluginConfig } from '../types'
import { scanComponents } from './utils'
import { watch } from 'chokidar'
import type { VitePlugin } from 'unplugin'
import { resolve } from 'pathe'

export function collectionsPlugin(config: PluginConfig): VitePlugin {
return {
name: 'compodium:collections',
configureServer(server) {
server.middlewares.use('/__compodium__/api/collections', async (_, res) => {
try {
const collections = await Promise.all([config.componentCollection, ...config.libraryCollections].map(async (col) => {
const components = await scanComponents(col.dirs, config.rootDir)
const examples = await scanComponents([col.exampleDir], config.rootDir)

const collectionComponents = components.map((c) => {
const componentExamples = examples?.filter(e => e.pascalName.startsWith(`${c.pascalName}Example`)).map(e => ({
...e,
isExample: true,
componentPath: resolve(config.rootDir, c.filePath)
}))

const mainExample = componentExamples.find(e => e.pascalName === `${c.pascalName}Example`)
const component = mainExample ?? c

return {
...component,
docUrl: col.getDocUrl?.(c.pascalName),
examples: componentExamples.filter(e => e.pascalName !== mainExample?.pascalName)
}
})

return {
...col,
components: collectionComponents
}
}))

res.setHeader('Content-Type', 'application/json')
res.write(JSON.stringify(collections))
res.end()
} catch {
res.statusCode = 500
res.end(JSON.stringify({ error: 'Failed to fetch collections' }))
}
})

const watchedPaths = [
...config.componentCollection.dirs,
config.componentCollection.exampleDir
].map(d => resolve(config.rootDir, d.path))

// Watch for changes in example directory
const watcher = watch(watchedPaths, {
persistent: true,
awaitWriteFinish: {
stabilityThreshold: 200,
pollInterval: 100
}
})

watcher.on('add', async (filePath: string) => {
if (watchedPaths.find(p => filePath.startsWith(p))) {
server.ws.send({
type: 'custom',
event: 'compodium:hmr',
data: { path: filePath, event: 'component:added' }
})
}
})

watcher.on('addDir', async (filePath: string) => {
if (watchedPaths.find(p => filePath.startsWith(p))) {
server.ws.send({
type: 'custom',
event: 'compodium:hmr',
data: { path: filePath, event: 'component:added' }
})
}
})

watcher.on('unlink', async (filePath: string) => {
if (watchedPaths.find(p => filePath.startsWith(p))) {
server.ws.send({
type: 'custom',
event: 'compodium:hmr',
data: { path: filePath, event: 'component:removed' }
})
}
})
}
}
}
Loading