### Install and Run Velite Example Source: https://github.com/zce/velite/blob/main/examples/basic/readme.md Install dependencies, run the build with watch mode, or perform a production build. ```shell $ npm install # install dependencies $ npm run dev # run build with watch mode $ npm run build # build content by velite ``` -------------------------------- ### Install rehype-highlight with yarn Source: https://github.com/zce/velite/blob/main/docs/guide/code-highlighting.md Install the rehype-highlight package using yarn. ```sh $ yarn add rehype-highlight ``` -------------------------------- ### Image Display Example Source: https://github.com/zce/velite/blob/main/examples/nextjs/content/pages/contact/index.mdx An example of how to embed an image with specified dimensions. ```mdx ``` -------------------------------- ### Install rehype-highlight with npm Source: https://github.com/zce/velite/blob/main/docs/guide/code-highlighting.md Install the rehype-highlight package using npm. ```sh $ npm install rehype-highlight ``` -------------------------------- ### Install rehype-highlight with pnpm Source: https://github.com/zce/velite/blob/main/docs/guide/code-highlighting.md Install the rehype-highlight package using pnpm. ```sh $ pnpm add rehype-highlight ``` -------------------------------- ### Install Velite with bun Source: https://github.com/zce/velite/blob/main/docs/guide/quick-start.md Install Velite as a development dependency using bun. ```sh $ bun add velite -D ``` -------------------------------- ### Install @shikijs/rehype and shiki Source: https://github.com/zce/velite/blob/main/docs/guide/code-highlighting.md Install the necessary packages for Shiki syntax highlighting using your preferred package manager. ```sh $ npm install @shikijs/rehype shiki ``` ```sh $ pnpm add @shikijs/rehype shiki ``` ```sh $ yarn add @shikijs/rehype shiki ``` -------------------------------- ### Install MDX Bundling Packages Source: https://github.com/zce/velite/blob/main/docs/guide/using-mdx.md Install esbuild and necessary plugins for bundling MDX files. This is the first step to enable MDX bundling. ```bash npm i esbuild @fal-works/esbuild-plugin-global-externals @mdx-js/esbuild --save-dev ``` -------------------------------- ### Install @shikijs/rehype with yarn Source: https://github.com/zce/velite/blob/main/docs/guide/code-highlighting.md Install the @shikijs/rehype package using yarn. ```sh $ yarn add @shikijs/rehype ``` -------------------------------- ### Install rehype-pretty-code with npm Source: https://github.com/zce/velite/blob/main/docs/guide/code-highlighting.md Install the rehype-pretty-code and shiki packages using npm. ```sh $ npm install rehype-pretty-code shiki ``` -------------------------------- ### Install rehype-pretty-code with yarn Source: https://github.com/zce/velite/blob/main/docs/guide/code-highlighting.md Install the rehype-pretty-code and shiki packages using yarn. ```sh $ yarn add rehype-pretty-code shiki ``` -------------------------------- ### Install rehype-pretty-code with pnpm Source: https://github.com/zce/velite/blob/main/docs/guide/code-highlighting.md Install the rehype-pretty-code and shiki packages using pnpm. ```sh $ pnpm add rehype-pretty-code shiki ``` -------------------------------- ### Install @shikijs/rehype with pnpm Source: https://github.com/zce/velite/blob/main/docs/guide/code-highlighting.md Install the @shikijs/rehype package using pnpm. ```sh $ pnpm add @shikijs/rehype ``` -------------------------------- ### Install Shiki Transformers Source: https://github.com/zce/velite/blob/main/docs/guide/code-highlighting.md Install the @shikijs/transformers package to enable advanced syntax highlighting features. ```sh $ npm install @shikijs/transformers ``` ```sh $ pnpm add @shikijs/transformers ``` ```sh $ yarn add @shikijs/transformers ``` -------------------------------- ### Install @shikijs/rehype with npm Source: https://github.com/zce/velite/blob/main/docs/guide/code-highlighting.md Install the @shikijs/rehype package using npm. ```sh $ npm install @shikijs/rehype ``` -------------------------------- ### Velite Installation and Build Commands Source: https://github.com/zce/velite/blob/main/docs/examples/basic.md Commands to install dependencies, run Velite in watch mode for development, and build content for production. ```shell $ npm install # install dependencies $ npm run dev # run build in watch mode $ npm run build # build content by velite ``` -------------------------------- ### Example Markdown Content File Source: https://github.com/zce/velite/blob/main/docs/guide/quick-start.md An example of a markdown file for a blog post, including frontmatter with metadata like title, slug, date, cover image, and video. ```md --- title: Hello world slug: hello-world date: 1992-02-25 13:22 cover: cover.jpg video: video.mp4 --- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse ![some image](img.png) [link to file](plain.txt) ``` -------------------------------- ### Install Velite and Vite Plugin Source: https://github.com/zce/velite/blob/main/packages/vite/readme.md Install velite and the vite plugin as development dependencies. ```bash npm install -D velite @velite/plugin-vite ``` -------------------------------- ### Markdown Tasklist Example Source: https://github.com/zce/velite/blob/main/examples/nextjs/content/pages/contact/index.mdx An example of a markdown tasklist showing to-do and completed items. ```markdown - [ ] to do - [x] done ``` -------------------------------- ### Install Velite with pnpm Source: https://github.com/zce/velite/blob/main/docs/guide/quick-start.md Install Velite as a development dependency using pnpm. ```sh $ pnpm add velite -D ``` -------------------------------- ### Install Velite with yarn Source: https://github.com/zce/velite/blob/main/docs/guide/quick-start.md Install Velite as a development dependency using yarn. ```sh $ yarn add velite -D ``` -------------------------------- ### Content Collection Structure Example Source: https://github.com/zce/velite/blob/main/docs/guide/define-collections.md Illustrates the directory structure for content collections within a project. Each top-level directory corresponds to a collection. ```text content ├── authors # => authors collection │ ├── zce.yml │ └── jane.yml ├── posts # => posts collection │ ├── hello-world.md │ └── another-post.md └── tags # => tags collection └── all-in-one.yml ``` -------------------------------- ### Start Velite Development Server with Options Source: https://github.com/zce/velite/blob/main/docs/reference/cli.md Run the development server with options such as specifying a config file, cleaning the output directory, or enabling debug mode. The server will watch for changes and rebuild automatically. ```sh $ velite dev -c --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

\"some

\n

link 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 } }) ```