--clean --verbose --silent --strict --debug
```
--------------------------------
### Default Callout Example
Source: https://github.com/zce/velite/blob/main/examples/nextjs/content/pages/contact/index.mdx
A standard callout box for general information.
```mdx
This is a default callout
```
--------------------------------
### Install Velite with npm
Source: https://github.com/zce/velite/blob/main/docs/guide/quick-start.md
Install Velite as a development dependency using npm.
```sh
$ npm install velite -D
```
--------------------------------
### Import Velite Output in Your Project
Source: https://github.com/zce/velite/blob/main/docs/guide/quick-start.md
Import the generated index.js file from the .velite directory to access your content. This example shows how to import and log the 'posts' collection.
```js
import { posts } from './.velite'
console.log(posts) // => [{ title: 'Hello world', slug: 'hello-world', ... }, ...]
```
--------------------------------
### Basic JavaScript Code Example
Source: https://github.com/zce/velite/blob/main/examples/basic/content/pages/contact/index.mdx
This snippet demonstrates a simple JavaScript function call. It's a placeholder for more complex logic.
```javascript
some.code()
```
--------------------------------
### Warning Callout Example
Source: https://github.com/zce/velite/blob/main/examples/nextjs/content/pages/contact/index.mdx
A callout box styled for warnings, highlighting important notices.
```mdx
This is a warning callout
```
--------------------------------
### Create Content Directory Structure
Source: https://github.com/zce/velite/blob/main/docs/guide/quick-start.md
Organize your creative content within the `content` directory. This example shows a typical structure for posts and other file types.
```diff
root
+├── content
+│ ├── posts
+│ │ └── hello-world.md
+│ └── others
+│ └── other.yml
├── public
├── package.json
└── velite.config.js
```
--------------------------------
### MDX Content Using a Common Component
Source: https://github.com/zce/velite/blob/main/docs/guide/using-mdx.md
An example MDX file demonstrating the usage of a common component ('Callout') without explicit import statements, relying on runtime injection.
```mdx
---
title: Foo
---
# Foo
This is foo callout.
```
--------------------------------
### Start Velite Development Server
Source: https://github.com/zce/velite/blob/main/docs/reference/cli.md
Build the project in watch mode for development. This command automatically rebuilds on file changes. Use the --config option to specify a different config file.
```sh
$ velite dev [options]
```
--------------------------------
### Client-side code highlighting with shiki
Source: https://github.com/zce/velite/blob/main/docs/guide/code-highlighting.md
Example of using shiki to highlight code blocks on the client-side. This method is recommended for a large number of documents to avoid impacting Velite's build speed.
```js
import { codeToHtml } from 'https://esm.sh/shikiji'
Array.from(document.querySelectorAll('pre code[class*="language-"]')).map(async block => {
block.parentElement.outerHTML = await codeToHtml(block.textContent, { lang: block.className.slice(9), theme: 'nord' })
})
```
--------------------------------
### Markdown Table Example
Source: https://github.com/zce/velite/blob/main/examples/nextjs/content/pages/contact/index.mdx
A basic markdown table structure with aligned columns.
```markdown
| a | b | c | d |
| --- | :-- | --: | :-: |
```
--------------------------------
### Example Posts Collection JSON Output
Source: https://github.com/zce/velite/blob/main/docs/guide/using-collections.md
This JSON represents the output of the 'posts' collection. It includes metadata, content, and references to static assets like images and videos.
```json
[
{
"title": "Hello world",
"slug": "hello-world",
"date": "1992-02-25T13:22:00.000Z",
"cover": {
"src": "/static/cover-2a4138dh.jpg",
"height": 1100,
"width": 1650,
"blurDataURL": "data:image/webp;base64,UklGRjwAAABXRUJQVlA4IDAAAACwAQCdASoIAAUADMDOJbACdADWaUXAAMltC0BZxTv24bHUX8EibgVs/sPiTqq6QAA=",
"blurWidth": 8,
"blurHeight": 5
},
"video": "/static/video-72hhd9f.mp4",
"metadata": {
"readingTime": 1,
"wordCount": 1
},
"excerpt": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse",
"content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse
\n
\nlink to file
\n",
"permalink": "/blog/hello-world"
}
]
```
--------------------------------
### Run Velite CLI with npm
Source: https://github.com/zce/velite/blob/main/docs/reference/cli.md
Execute Velite commands using npm. Ensure Velite is installed as a dev dependency or globally.
```sh
$ npx velite [options]
```
--------------------------------
### Velite Configuration Schema
Source: https://github.com/zce/velite/blob/main/examples/basic/content/posts/1970-01-01-style-guide/index.md
Example Velite configuration defining a 'posts' collection with a schema for markdown content. Use for setting up content collections and defining data structures.
```javascript
import { defineConfig, s } from 'velite'
// `s` is extended from Zod with some custom schemas,
// you can also import re-exported `z` from `velite` if you don't need these extension schemas.
export default defineConfig({
collections: {
posts: {
name: 'Post', // collection type name
pattern: 'posts/**/*.md', // content files glob pattern
schema: s
.object({
title: s.string().max(99), // Zod primitive type
slug: s.slug('posts'), // validate format, unique in posts collection
date: s.isodate(), // input Date-like string, output ISO Date string.
cover: s.image().optional(), // input image relpath, output image object with blurImage.
video: s.file().optional(), // input file relpath, output file public path.
metadata: s.metadata(), // extract markdown reading-time, word-count, etc.
excerpt: s.excerpt(), // excerpt of markdown content
content: s.markdown() // transform markdown to html
})
// more additional fields (computed fields)
.transform(data => ({ ...data, permalink: `/blog/${data.slug}` }))
},
others: {
// other collection schema options
}
}
})
```
--------------------------------
### Another MDX Content Using a Common Component
Source: https://github.com/zce/velite/blob/main/docs/guide/using-mdx.md
A second MDX file showcasing the use of the 'Callout' component, similar to the 'Foo' example, for demonstrating shared component availability.
```mdx
---
title: Bar
---
# Bar
This is bar callout.
```
--------------------------------
### Start Velite with Next.js Config (TypeScript)
Source: https://github.com/zce/velite/blob/main/docs/guide/with-nextjs.md
Integrates Velite build process into `next.config.ts` to run during development or build. This approach is recommended when Turbopack is enabled, as the `VeliteWebpackPlugin` may not function correctly.
```typescript
import type { NextConfig } from 'next'
const isDev = process.argv.indexOf('dev') !== -1
const isBuild = process.argv.indexOf('build') !== -1
if (!process.env.VELITE_STARTED && (isDev || isBuild)) {
process.env.VELITE_STARTED = '1'
import('velite').then(m => m.build({ watch: isDev, clean: !isDev }))
}
const nextConfig: NextConfig = {
/* config options here */
}
export default nextConfig
```
--------------------------------
### Import build function
Source: https://github.com/zce/velite/blob/main/docs/reference/api.md
Import the build function from the velite library to start building your project.
```typescript
import { build } from 'velite'
```
--------------------------------
### Danger Callout Example
Source: https://github.com/zce/velite/blob/main/examples/nextjs/content/pages/contact/index.mdx
A callout box styled for danger or critical alerts.
```mdx
This is a danger callout
```
--------------------------------
### Start Velite with Next.js Config (JavaScript Module)
Source: https://github.com/zce/velite/blob/main/docs/guide/with-nextjs.md
Integrates Velite build process into `next.config.mjs` using top-level await. This method is suitable for ESM-enabled Next.js configurations and runs during development or build.
```javascript
const isDev = process.argv.indexOf('dev') !== -1
const isBuild = process.argv.indexOf('build') !== -1
if (!process.env.VELITE_STARTED && (isDev || isBuild)) {
process.env.VELITE_STARTED = '1'
const { build } = await import('velite')
await build({ watch: isDev, clean: !isDev })
}
/** @type {import('next').NextConfig} */
export default {
// next config here...
}
```
--------------------------------
### Start Velite with Next.js Webpack Plugin (ESM)
Source: https://github.com/zce/velite/blob/main/docs/guide/with-nextjs.md
Integrates Velite's build process using a custom `VeliteWebpackPlugin` within an ESM-enabled `next.config.js`. This method leverages `import` syntax for Velite.
```javascript
import { build } from 'velite'
/** @type {import('next').NextConfig} */
export default {
// othor next config here...
webpack: config => {
config.plugins.push(new VeliteWebpackPlugin())
return config
}
}
class VeliteWebpackPlugin {
static started = false
apply(/** @type {import('webpack').Compiler} */ compiler) {
// executed three times in nextjs
// twice for the server (nodejs / edge runtime) and once for the client
compiler.hooks.beforeCompile.tapPromise('VeliteWebpackPlugin', async () => {
if (VeliteWebpackPlugin.started) return
VeliteWebpackPlugin.started = true
const dev = compiler.options.mode === 'development'
await build({ watch: dev, clean: !dev })
})
}
}
```
--------------------------------
### Define a Common Component for MDX
Source: https://github.com/zce/velite/blob/main/docs/guide/using-mdx.md
Example of a common React component that can be used within MDX files. This component is defined in a separate file.
```tsx
export const Callout = ({ children }: { children: React.ReactNode }) => {
// your common component
return {children}
}
```
--------------------------------
### Define and Use a Custom TOML Loader
Source: https://github.com/zce/velite/blob/main/docs/guide/custom-loader.md
Example of defining a custom loader for TOML files using `defineLoader` and integrating it into the Velite configuration. This loader parses TOML content into a JavaScript object.
```javascript
import toml from 'toml'
import { defineConfig, defineLoader } from 'velite'
const tomlLoader = defineLoader({
test: /\.toml$/,
load: vfile => {
return { data: toml.parse(vfile.toString()) }
}
})
export default defineConfig({
// ...
loaders: [tomlLoader]
})
```
--------------------------------
### Example CSS for rehype-pretty-code
Source: https://github.com/zce/velite/blob/main/docs/guide/code-highlighting.md
A sample CSS stylesheet demonstrating how to style code blocks processed by rehype-pretty-code, including line numbers and highlighted lines. This stylesheet uses Tailwind CSS directives.
```css
[data-rehype-pretty-code-figure] pre {
@apply px-0;
}
[data-rehype-pretty-code-figure] code {
@apply text-sm !leading-loose md:text-base;
}
[data-rehype-pretty-code-figure] code[data-line-numbers] {
counter-reset: line;
}
[data-rehype-pretty-code-figure] code[data-line-numbers] > [data-line]::before {
counter-increment: line;
content: counter(line);
@apply mr-4 inline-block w-4 text-right text-gray-500;
}
[data-rehype-pretty-code-figure] [data-line] {
@apply border-l-2 border-l-transparent px-3;
}
[data-rehype-pretty-code-figure] [data-highlighted-line] {
background: rgba(200, 200, 255, 0.1);
@apply border-l-blue-400;
}
[data-rehype-pretty-code-figure] [data-highlighted-chars] {
@apply rounded bg-zinc-600/50;
box-shadow: 0 0 0 4px rgb(82 82 91 / 0.5);
}
[data-rehype-pretty-code-figure] [data-chars-id] {
@apply border-b-2 p-1 shadow-none;
}
```
--------------------------------
### Start Velite with Next.js Webpack Plugin (CommonJS)
Source: https://github.com/zce/velite/blob/main/docs/guide/with-nextjs.md
Uses a custom `VeliteWebpackPlugin` within `next.config.js` to integrate Velite's build process. This approach is compatible with CommonJS module systems in Next.js.
```javascript
/** @type {import('next').NextConfig} */
module.exports = {
// othor next config here...
webpack: config => {
config.plugins.push(new VeliteWebpackPlugin())
return config
}
}
class VeliteWebpackPlugin {
static started = false
apply(/** @type {import('webpack').Compiler} */ compiler) {
// executed three times in nextjs
// twice for the server (nodejs / edge runtime) and once for the client
compiler.hooks.beforeCompile.tapPromise('VeliteWebpackPlugin', async () => {
if (VeliteWebpackPlugin.started) return
VeliteWebpackPlugin.started = true
const dev = compiler.options.mode === 'development'
const { build } = await import('velite')
await build({ watch: dev, clean: !dev })
})
}
}
```
--------------------------------
### Define Collections in Velite Config
Source: https://github.com/zce/velite/blob/main/docs/guide/quick-start.md
Create a velite.config.js file to define collections and their schemas. This example shows a 'posts' collection with various field types including string, slug, date, image, file, metadata, excerpt, and markdown.
```js
import { defineConfig, s } from 'velite'
// `s` is extended from Zod with some custom schemas,
// you can also import re-exported `z` from `velite` if you don't need these extension schemas.
export default defineConfig({
collections: {
posts: {
name: 'Post', // collection type name
pattern: 'posts/**/*.md', // content files glob pattern
schema: s
.object({
title: s.string().max(99), // Zod primitive type
slug: s.slug('posts'), // validate format, unique in posts collection
// slug: s.path(), // auto generate slug from file path
date: s.isodate(), // input Date-like string, output ISO Date string.
cover: s.image(), // input image relative path, output image object with blurImage.
video: s.file().optional(), // input file relative path, output file public path.
metadata: s.metadata(), // extract markdown reading-time, word-count, etc.
excerpt: s.excerpt(), // excerpt of markdown content
content: s.markdown() // transform markdown to html
})
// more additional fields (computed fields)
.transform(data => ({ ...data, permalink: `/blog/${data.slug}` }))
},
others: {
// other collection schema options
}
}
})
```
--------------------------------
### Copy File and Return URL with s.file()
Source: https://github.com/zce/velite/blob/main/docs/guide/velite-schemas.md
Use `s.file()` to copy a file relative to the current schema file into the output assets directory and get its public URL. It handles relative paths, checks for existence, and can optionally process absolute paths or URLs.
```typescript
avatar: s.file()
// case 1. relative path
// 'avatar.png' => '/static/avatar-34kjfdsi.png'
// case 2. non-exists file
// 'not-exists.png' => issue 'File not exists'
// case 3. absolute path or full url (if allowed)
// '/icon.png' => '/icon.png'
// 'https://zce.me/logo.png' => 'https://zce.me/logo.png'
```
--------------------------------
### Initialize Velite Project
Source: https://github.com/zce/velite/blob/main/docs/reference/cli.md
Initialize a new Velite project. This command is intended to create a default configuration file in the current directory. Further details on options are pending.
```sh
$ velite init [options]
```
--------------------------------
### Build Velite Project with Options
Source: https://github.com/zce/velite/blob/main/docs/reference/cli.md
Build the project with various options like cleaning the output directory, watching for changes, or enabling verbose logging. The default config file is used unless specified.
```sh
$ velite build -c --clean --watch --verbose --silent --strict --debug
```
--------------------------------
### build
Source: https://github.com/zce/velite/blob/main/docs/reference/api.md
Build your project. This function can be called with optional configuration options to customize the build process.
```APIDOC
## build
Build your project.
### Usage
```ts
import { build } from 'velite'
```
### Signature
```ts
const build: (options?: Options) => Promise
```
### Parameters
#### `options`
- Type: `Options`, See [Options](#options).
Options for build.
#### `options.config`
- Type: `string`
Specify the config file path.
#### `options.clean`
- Type: `boolean`
- Default: `false`
Clean output directories before build.
#### `options.watch`
- Type: `boolean`
- Default: `false`
Watch files and rebuild on changes.
#### `options.logLevel`
- Type: `'debug' | 'info' | 'warn' | 'error' | 'silent'`
- Default: `'info'`
Log level.
#### `options.strict`
- Type: `boolean`
- Default: `false`
If true, throws an error and terminates the process if any schema validation fails. Otherwise, a warning is logged but the process does not terminate.
### Returns
- Type: `Promise`, See [Result](#result).
The build result.
### Types
#### Options
```ts
interface Options {
/**
* Specify config file path
* @default 'velite.config.{js,ts,mjs,mts,cjs,cts}'
*/
config?: string
/**
* Clean output directories before build
* @default false
*/
clean?: boolean
/**
* Watch files and rebuild on changes
* @default false
*/
watch?: boolean
/**
* Log level
* @default 'info'
*/
logLevel?: LogLevel
}
```
#### Result
```ts
interface Entry {
[key: string]: any
}
/**
* build result, may be one or more entries in a document file
*/
interface Result {
[name: string]: Entry | Entry[]
}
```
```
--------------------------------
### context
Source: https://github.com/zce/velite/blob/main/docs/reference/api.md
Get the current parser context while Velite is parsing a schema. This is useful for accessing configuration and file information within schema callbacks.
```APIDOC
## context
Get the current parser context while Velite is parsing a schema.
### Usage
```ts
import { context } from 'velite'
```
### Signature
```ts
const context: () => ParserContext
```
### Returns
- Type: `ParserContext`, See [ParserContext](./types.md#parsercontext).
The parser context contains the resolved config and current file. Call `context()` inside schema callbacks such as `.transform()`, `.refine()`, or `.superRefine()`.
```
--------------------------------
### Build Velite Project
Source: https://github.com/zce/velite/blob/main/docs/reference/cli.md
Build the project contents using the default configuration file in the current directory. Use the --config option to specify a different config file.
```sh
$ velite build [options]
```
--------------------------------
### Velite Webpack Plugin for Next.js (ESM)
Source: https://github.com/zce/velite/blob/main/docs/other/snippets.md
This ESM configuration allows you to integrate the VeliteWebpackPlugin into your Next.js project. It requires Velite to be installed as a dev dependency.
```js
import { build } from 'velite'
/** @type {import('next').NextConfig} */
export default {
// othor next config here...
webpack: config => {
config.plugins.push(new VeliteWebpackPlugin())
return config
}
}
class VeliteWebpackPlugin {
static started = false
constructor(/** @type {import('velite').Options} */ options = {}) {
this.options = options
}
apply(/** @type {import('webpack').Compiler} */ compiler) {
// executed three times in nextjs !!!
// twice for the server (nodejs / edge runtime) and once for the client
compiler.hooks.beforeCompile.tapPromise('VeliteWebpackPlugin', async () => {
if (VeliteWebpackPlugin.started) return
VeliteWebpackPlugin.started = true
const dev = compiler.options.mode === 'development'
this.options.watch = this.options.watch ?? dev
this.options.clean = this.options.clean ?? !dev
await build(this.options) // start velite
})
}
}
```
--------------------------------
### Get Raw Document Body with s.raw()
Source: https://github.com/zce/velite/blob/main/docs/guide/velite-schemas.md
Use `s.raw()` to retrieve the unprocessed body of a document. This is useful when you need the exact content without any markdown parsing.
```typescript
code: s.raw()
// => raw document body
```
--------------------------------
### Velite Webpack Plugin for Next.js (CommonJS)
Source: https://github.com/zce/velite/blob/main/docs/other/snippets.md
Use this CommonJS configuration to add the VeliteWebpackPlugin to your Next.js project's webpack configuration. Ensure Velite is installed as a dev dependency.
```js
/** @type {import('next').NextConfig} */
module.exports = {
// othor next config here...
webpack: config => {
config.plugins.push(new VeliteWebpackPlugin())
return config
}
}
class VeliteWebpackPlugin {
static started = false
constructor(/** @type {import('velite').Options} */ options = {}) {
this.options = options
}
apply(/** @type {import('webpack').Compiler} */ compiler) {
// executed three times in nextjs !!!
// twice for the server (nodejs / edge runtime) and once for the client
compiler.hooks.beforeCompile.tapPromise('VeliteWebpackPlugin', async () => {
if (VeliteWebpackPlugin.started) return
VeliteWebpackPlugin.started = true
const dev = compiler.options.mode === 'development'
this.options.watch = this.options.watch ?? dev
this.options.clean = this.options.clean ?? !dev
const { build } = await import('velite')
await build(this.options) // start velite
})
}
}
```
--------------------------------
### Build Contents with Velite
Source: https://github.com/zce/velite/blob/main/docs/guide/quick-start.md
Run the `velite` command in your terminal to build your content. This command is available via npm, pnpm, yarn, and bun.
```sh
$ npx velite
```
```sh
$ pnpm velite
```
```sh
$ yarn velite
```
```sh
$ bun velite
```
--------------------------------
### Next.js Project Structure with Velite
Source: https://github.com/zce/velite/blob/main/docs/examples/nextjs.md
Illustrates the typical directory layout for a Next.js project utilizing Velite for content management. Shows where content files, configuration, and Next.js app files are located.
```text
nextjs
├── app # Next.js app directory
│ ├── layout.tsx
│ ├── page.tsx
│ └── etc...
├── components
│ ├── mdx-content.tsx
│ └── etc...
├── content # content directory
│ ├── categories
│ │ ├── journal.jpg
│ │ ├── journal.yml
│ │ └── etc...
│ ├── options
│ │ └── index.yml
│ ├── pages
│ │ ├── about
│ │ │ └── index.mdx
│ │ └── contact
| | ├── img.png and more...
│ │ └── index.mdx
│ ├── posts
│ │ ├── 1970-01-01-style-guide
│ │ │ ├── cover.jpg and more...
│ │ │ └── index.md
│ │ └── 1992-02-25-hello-world
│ │ ├── cover.jpg and more...
│ │ └── index.md
│ └── tags
│ └── index.yml
├── public # public directory
│ ├── favicon.ico
│ └── etc...
├── .gitignore
├── package.json
├── README.md
├── tsconfig.json
└── velite.config.ts # Velite config file
```
--------------------------------
### Define MDX Collection Schema in Velite
Source: https://github.com/zce/velite/blob/main/docs/guide/using-mdx.md
Use the `s.mdx()` schema to include compiled MDX content in your collections. This example defines a 'posts' collection with an MDX field named 'code'.
```js
import { defineConfig, s } from 'velite'
export default defineConfig({
collections: {
posts: {
name: 'Post',
pattern: 'posts/*.mdx',
schema: s.object({
title: s.string(),
code: s.mdx()
})
}
}
})
```
--------------------------------
### Run Velite CLI with Bun
Source: https://github.com/zce/velite/blob/main/docs/reference/cli.md
Execute Velite commands using Bun. Bun offers a fast alternative for running JavaScript and TypeScript projects.
```sh
$ bun velite [options]
```
--------------------------------
### Add Computed Fields with Schema Transform
Source: https://github.com/zce/velite/blob/main/docs/guide/define-collections.md
Use the `.transform()` method on Zod schemas to add computed fields to collection content items. This example adds a permalink based on a slug.
```javascript
const posts = defineCollection({
schema: s
.object({
slug: s.slug('posts')
})
.transform(data => ({
...data,
// computed fields
permalink: `/blog/${data.slug}`
}))
})
```
--------------------------------
### Options interface for build function
Source: https://github.com/zce/velite/blob/main/docs/reference/api.md
Defines the configuration options for the build function, including config file path, clean, watch, and logLevel.
```typescript
interface Options {
/**
* Specify config file path
* @default 'velite.config.{js,ts,mjs,mts,cjs,cts}'
*/
config?: string
/**
* Clean output directories before build
* @default false
*/
clean?: boolean
/**
* Watch files and rebuild on changes
* @default false
*/
watch?: boolean
/**
* Log level
* @default 'info'
*/
logLevel?: LogLevel
}
```
--------------------------------
### Typed Routes Schema Definition
Source: https://github.com/zce/velite/blob/main/docs/guide/with-nextjs.md
Example of defining a schema in Velite that includes a typed route for use with Next.js's `next/link` or `next/router` components. This enhances type safety for navigation.
```typescript
import type { Route } from 'next'
import type { Schema } from 'velite'
const options = defineCollection({
// ...
schema: s.object({
// ...
link: z.string() as Schema>
})
})
```
--------------------------------
### Include Raw and Plain Text Content Bodies
Source: https://github.com/zce/velite/blob/main/docs/guide/define-collections.md
Add the raw and plain text versions of a content's body as fields using custom schemas and `context().file.content` or `context().file.plain`. For most cases, `s.markdown()` or `s.mdx()` are preferred.
```javascript
import { context } from 'velite'
const posts = defineCollection({
schema: s.object({
content: s.custom().transform(() => context().file.content),
plain: s.custom().transform(() => context().file.plain)
})
})
```
--------------------------------
### Transform All Collections with defineConfig
Source: https://github.com/zce/velite/blob/main/docs/guide/introduction.md
Illustrates transforming all collections globally using the `prepare` hook in `defineConfig`.
```typescript
defineConfig({
prepare: async ({ posts, tags }) => {
posts.push({
title: 'Hello World',
slug: 'hello-world',
tags: ['hello', 'world']
})
tags.push({
name: 'Hello',
slug: 'hello'
})
}
})
```
--------------------------------
### Configure Asset Output and Complete Hook
Source: https://github.com/zce/velite/blob/main/docs/guide/asset-handling.md
Set the base URL for static assets and implement the `complete` hook to handle asset uploads. This hook is called after the build is complete.
```typescript
import { defineConfig } from 'velite'
export default defineConfig({
output: {
base: 'https://oss.your.com/static/'
},
complete: async () => {
// TODO: upload images
// static => https://oss.your.com/static/
}
})
```
--------------------------------
### s.file()
Source: https://github.com/zce/velite/blob/main/docs/guide/velite-schemas.md
Handles file paths relative to the current file. It copies the file to the `config.output.assets` directory and returns its public URL. Supports non-relative paths if configured.
```APIDOC
## `s.file(options)`
`string => string`
Handles file paths relative to the current file, copying the file to `config.output.assets` and returning the public URL.
### Parameters
##### **options.allowNonRelativePath**:
Allows non-relative paths. If true, the value is returned directly; otherwise, it's processed as a relative path.
- type: `boolean`
- default: `true`
```
--------------------------------
### Basic Velite Config File
Source: https://github.com/zce/velite/blob/main/docs/reference/config.md
Create a `velite.config.js` file in your project root to configure Velite. Supports JS, TS, ESM, and CommonJS.
```javascript
// velite.config.js
export default {
// ...
}
```
--------------------------------
### Define Multiple Collections in Velite
Source: https://github.com/zce/velite/blob/main/docs/guide/define-collections.md
Shows how to define multiple collections (posts, authors, tags) and configure them within the Velite defineConfig. Imports necessary functions from 'velite'.
```javascript
import { defineCollection, defineConfig, s } from 'velite'
const posts = defineCollection({
/* collection shema options */
})
const authors = defineCollection({
/* collection shema options */
})
const tags = defineCollection({
/* collection shema options */
})
export default defineConfig({
collections: { authors, posts, tags }
})
```
--------------------------------
### Define Timestamp Schema from Git Commit
Source: https://github.com/zce/velite/blob/main/docs/guide/last-modified.md
Define a custom Velite schema to capture the last modified timestamp from Git using `git log`. This schema executes a shell command to get the commit date and transforms it into an ISO string.
```typescript
import { exec } from 'child_process'
import { promisify } from 'util'
import { context, defineSchema, s } from 'velite'
const execAsync = promisify(exec)
const timestamp = defineSchema(() =>
s
.custom(i => i === undefined || typeof i === 'string')
.transform(async (value, { addIssue }) => {
if (value != null) {
addIssue({ fatal: false, code: 'custom', message: '`s.timestamp()` schema will resolve the value from `git log -1 --format=%cd`' })
}
const { stdout } = await execAsync(`git log -1 --format=%cd ${context().file.path}`)
return new Date(stdout || Date.now()).toISOString()
})
)
```
--------------------------------
### Configure Velite with Prepare Hook
Source: https://github.com/zce/velite/blob/main/docs/reference/config.md
Use the `prepare` hook to modify data before it's written to files. You can also access the resolved configuration via the context. Returning `false` prevents default file output.
```javascript
export default defineConfig({
collections: { posts, tags },
prepare: (data, context) => {
// modify data
data.posts.push({ ... })
data.tags.push({ ... })
// context
const { config } = context
// config is resolved from `velite.config.js` with default values
// return false to prevent the default output to a file
}
})
```
--------------------------------
### s.image()
Source: https://github.com/zce/velite/blob/main/docs/guide/velite-schemas.md
Processes image paths relative to the current file, similar to `s.file()`. It copies the image to `config.output.assets` and returns an `Image` object containing metadata and blur placeholder information.
```APIDOC
## `s.image(options)`
`string => Image`
Processes image paths relative to the current file, copying the image to `config.output.assets` and returning an `Image` object with metadata.
### Parameters
##### **options.absoluteRoot**:
Root path for absolute paths. If provided, the value is processed as an absolute path.
- type: `string`
- default: `undefined`
##### **options.blur**:
Options for generating a blur placeholder, customizing the `blurDataURL`.
- type: `{ width?: number; height?: number; quality?: number }`
- default: `undefined`
- `blur.width`: Blur image width. default: `8`
- `blur.height`: Blur image height. default: derived from the image aspect ratio
- `blur.quality`: WebP quality of the blur image (1-100). default: `1`
```
--------------------------------
### Process Image and Return Metadata with s.image()
Source: https://github.com/zce/velite/blob/main/docs/guide/velite-schemas.md
Use `s.image()` to copy an image file, return its public URL along with metadata (dimensions, blur placeholder), and optionally configure blur options like width and quality.
```typescript
avatar: s.image()
// case 1. relative path
// 'avatar.png' => {
// src: '/static/avatar-34kjfdsi.png',
// width: 100,
// height: 100,
// blurDataURL: 'data:image/png;base64,xxx',
// blurWidth: 8,
// blurHeight: 8
// }
// case 2. non-exists file
// 'not-exists.png' => issue 'File not exists'
// case 3. absolute path or full url (if allowed)
// '/icon.png' => { src: '/icon.png', width: 0, height: 0, blurDataURL: '', blurWidth: 0, blurHeight: 0 }
// 'https://zce.me/logo.png' => { src: 'https://zce.me/logo.png', width: 0, height: 0, blurDataURL: '', blurWidth: 0, blurHeight: 0 }
```
--------------------------------
### Adding Global Components to MDXContent
Source: https://github.com/zce/velite/blob/main/docs/guide/using-mdx.md
Illustrates how to configure the MDXContent component to include global components like 'Callout' that are accessible across all MDX files without explicit imports in each file.
```tsx
import * as runtime from 'react/jsx-runtime'
import { Callout } from '@/components/callout'
const sharedComponents = {
// Add your global components here
Callout
}
const useMDXComponent = (code: string) => {
const fn = new Function(code)
return fn({ ...runtime }).default
}
interface MDXProps {
code: string
components?: Record
}
export const MDXContent = ({ code, components }: MDXProps) => {
const Component = useMDXComponent(code)
return
}
```
--------------------------------
### Configure Blur Options for s.image()
Source: https://github.com/zce/velite/blob/main/docs/guide/velite-schemas.md
Customize the blur placeholder for `s.image()` by providing options for width and quality. The height is derived from the image's aspect ratio.
```typescript
avatar: s.image({ blur: { width: 16, quality: 30 } })
```
--------------------------------
### MDX Bundler with ESBuild
Source: https://github.com/zce/velite/blob/main/docs/other/snippets.md
Bundles MDX files into a single JavaScript module using esbuild. Includes plugins for virtual sources and global externals.
```tsx
import { join, resolve } from 'node:path'
import { globalExternals } from '@fal-works/esbuild-plugin-global-externals'
import mdxPlugin from '@mdx-js/esbuild'
import { build } from 'esbuild'
import type { Plugin } from 'esbuild'
const compileMdx = async (source: string): Promise => {
const virtualSourse: Plugin = {
name: 'virtual-source',
setup: build => {
build.onResolve({ filter: /^__faker_entry/ }, args => {
return {
path: join(args.resolveDir, args.path),
pluginData: { contents: source } // for mdxPlugin
}
})
}
}
const bundled = await build({
entryPoints: [`__faker_entry.mdx`],
absWorkingDir: resolve('content'),
write: false,
bundle: true,
target: 'node18',
platform: 'neutral',
format: 'esm',
globalName: 'VELITE_MDX_COMPONENT',
treeShaking: true,
jsx: 'automatic',
// minify: true,
plugins: [
virtualSourse,
mdxPlugin({}),
globalExternals({
react: {
varName: 'React',
type: 'cjs'
},
'react-dom': {
varName: 'ReactDOM',
type: 'cjs'
},
'react/jsx-runtime': {
varName: '_jsx_runtime',
type: 'cjs'
}
})
]
})
return bundled.outputFiles[0].text.replace('var VELITE_MDX_COMPONENT=', 'return ')
}
```
--------------------------------
### Injecting Custom Components into MDXContent
Source: https://github.com/zce/velite/blob/main/docs/guide/using-mdx.md
Demonstrates how to pass custom components, such as 'Callout', to the MDXContent component during runtime. This allows MDX files to use components not bundled at build time.
```tsx
import { Callout } from '@/components/callout'
import { MDXContent } from '@/components/mdx-content'
export default function Post({ params: { slug } }) {
const post = posts.find(i => i.slug === slug)
return (
{post.title}
)
}
```
--------------------------------
### Custom MDX Bundling Schema
Source: https://github.com/zce/velite/blob/main/docs/guide/using-mdx.md
Create a custom esbuild-based schema to compile and bundle MDX content. This schema handles the compilation process, including virtual source injection and external dependency management.
```typescript
import { dirname, join } from 'node:path'
import { globalExternals } from '@fal-works/esbuild-plugin-global-externals'
import mdxPlugin from '@mdx-js/esbuild'
import { build } from 'esbuild'
import { context, s } from 'velite'
import type { Plugin } from 'esbuild'
const compileMdx = async (source: string, path: string, options: CompileOptions): Promise => {
const virtualSourse: Plugin = {
name: 'virtual-source',
setup: build => {
build.onResolve({ filter: /^__faker_entry/ }, args => {
return {
path: join(args.resolveDir, args.path),
pluginData: { contents: source } // for mdxPlugin
}
})
}
}
const bundled = await build({
entryPoints: [`__faker_entry.mdx`],
absWorkingDir: dirname(path),
write: false,
bundle: true,
target: 'node18',
platform: 'neutral',
format: 'esm',
globalName: 'VELITE_MDX_COMPONENT',
treeShaking: true,
jsx: 'automatic',
minify: true,
plugins: [
virtualSourse,
mdxPlugin({}),
globalExternals({
react: {
varName: 'React',
type: 'cjs'
},
'react-dom': {
varName: 'ReactDOM',
type: 'cjs'
},
'react/jsx-runtime': {
varName: '_jsx_runtime',
type: 'cjs'
}
})
]
})
return bundled.outputFiles[0].text.replace('var VELITE_MDX_COMPONENT=', 'return ')
}
export const mdxBundle = (options: MdxOptions = {}) =
s.custom().transform(async (value, { addIssue }) => {
const { config, file } = context()
const { path, content } = file
value = value ?? content
if (value == null) {
addIssue({ fatal: true, code: 'custom', message: 'The content is empty' })
return null as never
}
const enableGfm = options.gfm ?? config.mdx?.gfm ?? true
const enableMinify = options.minify ?? config.mdx?.minify ?? true
const removeComments = options.removeComments ?? config.mdx?.removeComments ?? true
const copyLinkedFiles = options.copyLinkedFiles ?? config.mdx?.copyLinkedFiles ?? true
const outputFormat = options.outputFormat ?? config.mdx?.outputFormat ?? 'function-body'
const remarkPlugins = [] as PluggableList
const rehypePlugins = [] as PluggableList
if (enableGfm) remarkPlugins.push(remarkGfm) // support gfm (autolink literals, footnotes, strikethrough, tables, tasklists).
if (removeComments) remarkPlugins.push(remarkRemoveComments) // remove html comments
if (copyLinkedFiles) remarkPlugins.push([remarkCopyLinkedFiles, config.output]) // copy linked files to public path and replace their urls with public urls
if (options.remarkPlugins != null) remarkPlugins.push(...options.remarkPlugins) // apply remark plugins
if (options.rehypePlugins != null) rehypePlugins.push(...options.rehypePlugins) // apply rehype plugins
if (config.mdx?.remarkPlugins != null) remarkPlugins.push(...config.mdx.remarkPlugins) // apply global remark plugins
if (config.mdx?.rehypePlugins != null) rehypePlugins.push(...config.mdx.rehypePlugins) // apply global rehype plugins
const compilerOptions = { ...config.mdx, ...options, outputFormat, remarkPlugins, rehypePlugins }
try {
return await compileMdx(value, path, compilerOptions)
} catch (err: any) {
addIssue({ fatal: true, code: 'custom', message: err.message })
return null as never
}
})
```