与 Next.js 集成
Velite 是一个框架无关的库,可用于任何 JavaScript 框架或库,包括 Next.js。
以下是一些方案,可帮助您更好地将 Velite 与 Next.js 集成。
🎊 使用 Next.js 配置启动 Velite 🆕
Next.js 正逐步采用 Turbopack,因为它速度显著更快。然而,Turbopack 与 Webpack 生态系统不完全兼容,这意味着启用 Turbopack 时,VeliteWebpackPlugin 无法正常工作。以下是一个全新的解决方案。
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 nextConfigconst 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...
}请注意,此方法使用了顶级 await,因此仅支持 next.config.mjs 或启用了 ESM 的情况。
使用 Next.js Webpack 插件启动 Velite
您可以使用 Next.js 插件调用 Velite 的编程 API,以更好地集成并启动 Velite。
在 next.config.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
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 })
})
}
}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 })
})
}
}INFO
ESM import { build } from 'velite' 在 next build 过程中可能会收到 [webpack.cache.PackFileCacheStrategy/webpack.FileSystemInfo] 警告,影响不大。 请参考 https://github.com/webpack/webpack/pull/15688
或 👆
在 npm 脚本中使用 npm-run-all 启动 Velite:
INFO
推荐使用 VeliteWebpackPlugin,但如果您的项目部署在 Vercel 上,可能会出现 free(): invalid size 或 munmap_chunk(): invalid pointer 错误,这通常与 sharp 模块相关。请参考:https://github.com/zce/velite/issues/52#issuecomment-2016789204
package.json:
{
"scripts": {
"dev:content": "velite --watch",
"build:content": "velite --clean",
"dev:next": "next dev",
"build:next": "next build",
"dev": "run-p dev:*",
"build": "run-s build:*",
"start": "next start"
}
}类型化路由
当您使用 typedRoutes 实验性功能时,可以在 Next.js 应用中获取类型化路由。
在这种情况下,您可以为相关模式指定更具体的类型,以便在 next/link 或 next/router 上更轻松地使用。
例如:
import type { Route } from 'next'
import type { Schema } from 'velite'
const options = defineCollection({
// ...
schema: s.object({
// ...
link: z.string() as Schema<Route<'/posts/${string}'>>
})
})然后您可以像这样使用它:
import Link from 'next/link'
import { options } from '@/.velite'
const Post = async () => {
return (
<div>
{/* typed route */}
<Link href={options.link}>阅读更多</Link>
</div>
)
}