mirror of
https://github.com/wavetermdev/docusaurus-og.git
synced 2026-08-05 13:46:35 -07:00
feat: auto generate opengraph images
This commit is contained in:
@@ -19,6 +19,7 @@ coverage
|
||||
.cache-loader
|
||||
|
||||
packages/logos-*/lib/*
|
||||
packages/docusaurus-*/lib/*
|
||||
packages/logos-docusaurus-preset/static/common/data/team.json
|
||||
|
||||
lerna-debug.log
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "@acid-info/docusaurus-og",
|
||||
"version": "1.0.0-alpha.44",
|
||||
"description": "Docusaurus local search plugin",
|
||||
"main": "lib/index.js",
|
||||
"types": "src/plugin.d.ts",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/acid-info/logos-docusaurus-plugins.git",
|
||||
"directory": "packages/docusaurus-search-local"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "tsc --build",
|
||||
"watch": "tsc --build --watch",
|
||||
"prepublishOnly": "yarn build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "^2.4.1",
|
||||
"@docusaurus/module-type-aliases": "^2.4.1",
|
||||
"@docusaurus/types": "^2.4.1",
|
||||
"@docusaurus/utils": "^2.4.1",
|
||||
"@docusaurus/utils-common": "^2.4.1",
|
||||
"@docusaurus/utils-validation": "^2.4.1",
|
||||
"@easyops-cn/docusaurus-search-local": "^0.33.6",
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.186"
|
||||
},
|
||||
"gitHead": "d2ee08c6c0678f78ad70f5d04183f7f781d11563"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { LoadContext, Plugin } from '@docusaurus/types'
|
||||
import { postBuildFactory } from './server/index'
|
||||
import { PluginOptions } from './server/types/plugin.types'
|
||||
export { imageRendererFactory } from './server/imageRenderer.factory'
|
||||
export * from './server/types'
|
||||
export type { PluginOptions }
|
||||
|
||||
export default function logosTheme(
|
||||
context: LoadContext,
|
||||
options: PluginOptions,
|
||||
): Plugin<any> {
|
||||
return {
|
||||
name: 'docusaurus-og',
|
||||
|
||||
async postBuild(props) {
|
||||
await postBuildFactory(options)(props)
|
||||
},
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export type * from './index'
|
||||
@@ -0,0 +1,125 @@
|
||||
import {
|
||||
BlogContent,
|
||||
PluginOptions as BlogPluginOptions,
|
||||
} from '@docusaurus/plugin-content-blog'
|
||||
import { LoadedPlugin, Props } from '@docusaurus/types'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import { Document } from './document'
|
||||
import { ImageGenerator } from './imageGenerator'
|
||||
import { BlogPageData } from './types/blog.types'
|
||||
import { ImageRenderer } from './types/image.types'
|
||||
import { PluginOptions } from './types/plugin.types'
|
||||
|
||||
export class BlogPlugin {
|
||||
static plugin = 'docusaurus-plugin-content-blog'
|
||||
|
||||
pages: BlogPageData[] = []
|
||||
|
||||
constructor(
|
||||
private context: Props,
|
||||
private options: PluginOptions,
|
||||
private imageGenerator: ImageGenerator,
|
||||
private imageRenderer: ImageRenderer,
|
||||
) {}
|
||||
|
||||
process = async () => {
|
||||
await this.loadData()
|
||||
await this.generate()
|
||||
}
|
||||
|
||||
loadData = async () => {
|
||||
const plugins = this.context.plugins.filter(
|
||||
(plugin) => plugin.name === BlogPlugin.plugin,
|
||||
)
|
||||
|
||||
for (const plugin of plugins) {
|
||||
await this.loadInstance(plugin)
|
||||
}
|
||||
}
|
||||
|
||||
loadInstance = async (plugin: LoadedPlugin) => {
|
||||
const content = plugin.content as BlogContent
|
||||
const options = plugin.options as BlogPluginOptions
|
||||
|
||||
content.blogListPaginated.forEach((value) => {
|
||||
this.pages.push({
|
||||
data: value,
|
||||
plugin: options,
|
||||
pageType: 'list',
|
||||
permalink: value.metadata.permalink,
|
||||
})
|
||||
})
|
||||
|
||||
content.blogPosts.forEach((post) => {
|
||||
this.pages.push({
|
||||
data: post,
|
||||
plugin: options,
|
||||
pageType: 'post',
|
||||
permalink: post.metadata.permalink,
|
||||
})
|
||||
})
|
||||
|
||||
if (content.blogTagsListPath) {
|
||||
const filePath = this.getHtmlPath(content.blogTagsListPath)
|
||||
fs.existsSync(filePath) &&
|
||||
this.pages.push({
|
||||
pageType: 'tags',
|
||||
plugin: options,
|
||||
data: {
|
||||
permalink: content.blogTagsListPath,
|
||||
},
|
||||
permalink: content.blogTagsListPath,
|
||||
})
|
||||
}
|
||||
|
||||
if (options.archiveBasePath) {
|
||||
this.pages.push({
|
||||
plugin: options,
|
||||
pageType: 'archive',
|
||||
data: { permalink: options.archiveBasePath },
|
||||
permalink: options.archiveBasePath,
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
Object.entries(content.blogTags).map(([key, value]) => {
|
||||
value.pages.forEach((page) => {
|
||||
this.pages.push({
|
||||
pageType: 'tag',
|
||||
plugin: options,
|
||||
data: { ...page.metadata, label: value.label },
|
||||
permalink: page.metadata.permalink,
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
generate = async () => {
|
||||
for (const page of this.pages) {
|
||||
const image = await this.imageRenderer(
|
||||
{
|
||||
...page,
|
||||
websiteOutDir: this.context.outDir,
|
||||
},
|
||||
this.context,
|
||||
)
|
||||
|
||||
if (!image) continue
|
||||
|
||||
const generated = await this.imageGenerator.generate(...image)
|
||||
const document = new Document(this.getHtmlPath(page.permalink))
|
||||
|
||||
await document.load()
|
||||
if (!document.loaded) continue
|
||||
|
||||
await document.setImage(generated.url)
|
||||
|
||||
await document.write()
|
||||
}
|
||||
}
|
||||
|
||||
getHtmlPath = (permalink: string) =>
|
||||
path.join(this.context.outDir, permalink, 'index.html')
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import {
|
||||
LoadedContent,
|
||||
LoadedVersion,
|
||||
PluginOptions as DocsPluginOptions,
|
||||
} from '@docusaurus/plugin-content-docs'
|
||||
import { LoadedPlugin, Props } from '@docusaurus/types'
|
||||
import * as path from 'path'
|
||||
import { Document } from './document'
|
||||
import { ImageGenerator } from './imageGenerator'
|
||||
import { DocsPageData } from './types/docs.types'
|
||||
import { ImageRenderer } from './types/image.types'
|
||||
import { PluginOptions } from './types/plugin.types'
|
||||
|
||||
export class DocsPlugin {
|
||||
static plugin = 'docusaurus-plugin-content-docs'
|
||||
|
||||
docs: DocsPageData[] = []
|
||||
|
||||
constructor(
|
||||
private context: Props,
|
||||
private options: PluginOptions,
|
||||
private imageGenerator: ImageGenerator,
|
||||
private imageRenderer: ImageRenderer,
|
||||
) {}
|
||||
|
||||
process = async () => {
|
||||
await this.loadData()
|
||||
await this.generate()
|
||||
}
|
||||
|
||||
loadData = async () => {
|
||||
const { plugins = [] } = this.context
|
||||
|
||||
const docPlugins = plugins.filter(
|
||||
(plugin) => plugin.name === DocsPlugin.plugin,
|
||||
)
|
||||
|
||||
for (const plugin of docPlugins) {
|
||||
await this.loadInstance(plugin)
|
||||
}
|
||||
}
|
||||
|
||||
loadInstance = async (plugin: LoadedPlugin) => {
|
||||
const content = plugin.content as LoadedContent
|
||||
const options = plugin.options as DocsPluginOptions
|
||||
|
||||
const { loadedVersions } = content
|
||||
|
||||
for (const version of loadedVersions) {
|
||||
await this.loadVersion(options, version)
|
||||
}
|
||||
}
|
||||
|
||||
loadVersion = async (options: DocsPluginOptions, version: LoadedVersion) => {
|
||||
this.docs.push(
|
||||
...version.docs.map((doc) => ({
|
||||
version,
|
||||
metadata: doc,
|
||||
plugin: options,
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
generate = async () => {
|
||||
for (const doc of this.docs) {
|
||||
const image = await this.imageRenderer(
|
||||
{
|
||||
...doc,
|
||||
websiteOutDir: this.context.outDir,
|
||||
},
|
||||
this.context,
|
||||
)
|
||||
|
||||
if (!image) continue
|
||||
|
||||
const generated = await this.imageGenerator.generate(...image)
|
||||
const document = new Document(this.getHtmlPath(doc))
|
||||
await document.load()
|
||||
await document.setImage(generated.url)
|
||||
|
||||
await document.write()
|
||||
}
|
||||
}
|
||||
|
||||
getHtmlPath = (doc: DocsPageData) =>
|
||||
path.join(this.context.outDir, doc.metadata.permalink, 'index.html')
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import * as fsp from 'fs/promises'
|
||||
import { HTMLElement, parse as parseHTML } from 'node-html-parser'
|
||||
|
||||
export class Document {
|
||||
root: HTMLElement
|
||||
loaded = false
|
||||
|
||||
constructor(private path: string) {}
|
||||
|
||||
load = async () => {
|
||||
const htmlString = await fsp.readFile(this.path, 'utf-8')
|
||||
this.root = parseHTML(htmlString)
|
||||
this.loaded = true
|
||||
}
|
||||
|
||||
write = async () => {
|
||||
await fsp.writeFile(this.path, Buffer.from(this.root.outerHTML))
|
||||
}
|
||||
|
||||
setImage = async (url: string) => {
|
||||
this.updateMeta('property', 'og:image', {
|
||||
content: url,
|
||||
})
|
||||
this.updateMeta('property', 'image', {
|
||||
content: url,
|
||||
})
|
||||
}
|
||||
|
||||
get head() {
|
||||
return this.root.querySelector('head')!
|
||||
}
|
||||
|
||||
private getMeta(attr: string, value: string) {
|
||||
const { head } = this
|
||||
|
||||
let meta = head.querySelector(`meta[${attr}=${value}]`)
|
||||
|
||||
if (!meta) {
|
||||
meta = new HTMLElement('meta', {}, '', null, [0, 0])
|
||||
meta.setAttribute(attr, value)
|
||||
head.appendChild(meta)
|
||||
}
|
||||
|
||||
return meta
|
||||
}
|
||||
|
||||
private updateMeta = (
|
||||
attr: string,
|
||||
value: string,
|
||||
attrs: Record<string, any>,
|
||||
) => {
|
||||
const el = this.getMeta(attr, value)
|
||||
Object.entries(attrs).forEach(([key, value]) => el.setAttribute(key, value))
|
||||
|
||||
return el
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import * as fs from 'fs'
|
||||
import * as fsp from 'fs/promises'
|
||||
import hashObj from 'object-hash'
|
||||
import path from 'path'
|
||||
import React from 'react'
|
||||
|
||||
// @ts-expect-error
|
||||
import type Satori from 'satori'
|
||||
// @ts-expect-error
|
||||
import { type SatoriOptions } from 'satori'
|
||||
import type Sharp from 'sharp'
|
||||
|
||||
export type ImageGeneratorOptions = SatoriOptions
|
||||
export type ImageGeneratorResult = {
|
||||
url: string
|
||||
relativePath: string
|
||||
absolutePath: string
|
||||
}
|
||||
|
||||
export class ImageGenerator {
|
||||
private satori: typeof Satori
|
||||
private sharp: typeof Sharp
|
||||
private cache: Record<string, ImageGeneratorResult> = {}
|
||||
|
||||
private outDir: string = ''
|
||||
|
||||
constructor(
|
||||
private args: {
|
||||
dir: string
|
||||
websiteUrl: string
|
||||
websiteOutDir: string
|
||||
},
|
||||
) {
|
||||
this.outDir = path.join(this.args.websiteOutDir, this.args.dir)
|
||||
}
|
||||
|
||||
public init = async () => {
|
||||
this.satori = await import('satori').then((mod) => mod.default)
|
||||
this.sharp = await import('sharp').then((mod) => mod.default)
|
||||
|
||||
if (!fs.existsSync(this.outDir))
|
||||
await fsp.mkdir(this.outDir, { recursive: true })
|
||||
}
|
||||
|
||||
public generate = async (
|
||||
element: React.ReactNode,
|
||||
options: ImageGeneratorOptions,
|
||||
): Promise<ImageGeneratorResult> => {
|
||||
const hash = hashObj([element, options])
|
||||
if (this.cache[hash]) return this.cache[hash]!
|
||||
|
||||
const imageName = `${hash}.png`
|
||||
const absolutePath = path.join(this.outDir, imageName)
|
||||
const relativePath = path.join(
|
||||
'/',
|
||||
this.args.dir,
|
||||
absolutePath.slice(this.outDir.length),
|
||||
)
|
||||
|
||||
const svg = await this.satori(element, options)
|
||||
await this.sharp(Buffer.from(svg)).png().toFile(absolutePath)
|
||||
|
||||
const url = new URL(this.args.websiteUrl)
|
||||
url.pathname = relativePath
|
||||
|
||||
this.cache[hash] = {
|
||||
relativePath,
|
||||
absolutePath,
|
||||
url: url.toString(),
|
||||
}
|
||||
|
||||
return this.cache[hash]!
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { PageData } from '../index'
|
||||
import { BlogPageData } from './types/blog.types'
|
||||
import { DocsPageData } from './types/docs.types'
|
||||
import { ImageRenderer } from './types/image.types'
|
||||
|
||||
export function imageRendererFactory(
|
||||
plugin: 'docusaurus-plugin-content-docs',
|
||||
handler: ImageRenderer<DocsPageData>,
|
||||
): ImageRenderer
|
||||
export function imageRendererFactory(
|
||||
plugin: 'docusaurus-plugin-content-blog',
|
||||
handler: ImageRenderer<BlogPageData>,
|
||||
): ImageRenderer
|
||||
export function imageRendererFactory(
|
||||
plugin: 'docusaurus-plugin-content-pages',
|
||||
handler: ImageRenderer<PageData>,
|
||||
): ImageRenderer
|
||||
export function imageRendererFactory(
|
||||
plugin:
|
||||
| 'docusaurus-plugin-content-blog'
|
||||
| 'docusaurus-plugin-content-docs'
|
||||
| 'docusaurus-plugin-content-pages',
|
||||
handler: ImageRenderer,
|
||||
): ImageRenderer {
|
||||
return handler
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Props } from '@docusaurus/types'
|
||||
import { BlogPlugin } from './blog.plugin'
|
||||
import { DocsPlugin } from './docs.plugin'
|
||||
import { ImageGenerator } from './imageGenerator'
|
||||
import { PagesPlugin } from './pages.plugin'
|
||||
import { PluginOptions } from './types/plugin.types'
|
||||
|
||||
const plugins = {
|
||||
[DocsPlugin.plugin]: DocsPlugin,
|
||||
[BlogPlugin.plugin]: BlogPlugin,
|
||||
[PagesPlugin.plugin]: PagesPlugin,
|
||||
}
|
||||
|
||||
export const postBuildFactory =
|
||||
(options: PluginOptions) => async (props: Props) => {
|
||||
const imageGenerator = new ImageGenerator({
|
||||
websiteUrl: props.siteConfig.url,
|
||||
websiteOutDir: props.outDir,
|
||||
dir: options.path,
|
||||
})
|
||||
|
||||
await imageGenerator.init()
|
||||
|
||||
const pluginNames = Object.keys(options.imageRenderers)
|
||||
|
||||
for (const pluginName of pluginNames) {
|
||||
const renderer = options.imageRenderers[pluginName]
|
||||
const Plugin = plugins[pluginName]
|
||||
const plugin =
|
||||
Plugin && new Plugin(props, options, imageGenerator, renderer!)
|
||||
|
||||
plugin && (await plugin.process())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import {
|
||||
LoadedContent,
|
||||
PluginOptions as PagesPluginOptions,
|
||||
} from '@docusaurus/plugin-content-pages'
|
||||
import { LoadedPlugin, Props } from '@docusaurus/types'
|
||||
import * as path from 'path'
|
||||
import { PageData } from '../index'
|
||||
import { Document } from './document'
|
||||
import { ImageGenerator } from './imageGenerator'
|
||||
import { ImageRenderer } from './types/image.types'
|
||||
import { PluginOptions } from './types/plugin.types'
|
||||
|
||||
export class PagesPlugin {
|
||||
static plugin = 'docusaurus-plugin-content-pages'
|
||||
|
||||
pages: PageData[] = []
|
||||
|
||||
constructor(
|
||||
private context: Props,
|
||||
private options: PluginOptions,
|
||||
private imageGenerator: ImageGenerator,
|
||||
private imageRenderer: ImageRenderer,
|
||||
) {}
|
||||
|
||||
process = async () => {
|
||||
await this.loadData()
|
||||
await this.generate()
|
||||
}
|
||||
|
||||
loadData = async () => {
|
||||
const plugins = this.context.plugins.filter(
|
||||
(plugin) => plugin.name === PagesPlugin.plugin,
|
||||
)
|
||||
|
||||
for (const plugin of plugins) {
|
||||
await this.loadInstance(plugin)
|
||||
}
|
||||
}
|
||||
|
||||
loadInstance = async (plugin: LoadedPlugin) => {
|
||||
const content = plugin.content as LoadedContent
|
||||
const options = plugin.options as PagesPluginOptions
|
||||
|
||||
for (const metadata of content) {
|
||||
const doc = new Document(this.getHtmlPath(metadata.permalink))
|
||||
await doc.load()
|
||||
|
||||
const title =
|
||||
(doc.loaded && doc.root.querySelector('title')?.textContent) || ''
|
||||
|
||||
const description =
|
||||
(doc.loaded &&
|
||||
doc.root.querySelector('meta[name=description]')?.textContent) ||
|
||||
''
|
||||
|
||||
this.pages.push({
|
||||
metadata: {
|
||||
...metadata,
|
||||
title,
|
||||
description,
|
||||
},
|
||||
plugin: options,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
generate = async () => {
|
||||
for (const page of this.pages) {
|
||||
const image = await this.imageRenderer(
|
||||
{
|
||||
...page,
|
||||
websiteOutDir: this.context.outDir,
|
||||
},
|
||||
this.context,
|
||||
)
|
||||
|
||||
if (!image) continue
|
||||
|
||||
const generated = await this.imageGenerator.generate(...image)
|
||||
const document = new Document(this.getHtmlPath(page.metadata.permalink))
|
||||
|
||||
await document.load()
|
||||
if (!document.loaded) continue
|
||||
|
||||
await document.setImage(generated.url)
|
||||
|
||||
await document.write()
|
||||
}
|
||||
}
|
||||
|
||||
getHtmlPath = (permalink: string) =>
|
||||
path.join(this.context.outDir, permalink, 'index.html')
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import {
|
||||
BlogPaginated,
|
||||
BlogPost,
|
||||
BlogTag,
|
||||
PluginOptions,
|
||||
} from '@docusaurus/plugin-content-blog'
|
||||
|
||||
export type BlogPageType =
|
||||
| 'post'
|
||||
| 'list'
|
||||
| 'archive'
|
||||
| 'tags'
|
||||
| 'tag'
|
||||
| 'archive'
|
||||
|
||||
export type BlogPageData = {
|
||||
plugin: PluginOptions
|
||||
permalink: string
|
||||
} & (
|
||||
| {
|
||||
pageType: Extract<BlogPageType, 'post'>
|
||||
data: BlogPost
|
||||
}
|
||||
| {
|
||||
pageType: Extract<BlogPageType, 'list'>
|
||||
data: BlogPaginated
|
||||
}
|
||||
| {
|
||||
pageType: Extract<BlogPageType, 'tags'>
|
||||
data: {
|
||||
permalink: string
|
||||
}
|
||||
}
|
||||
| {
|
||||
pageType: Extract<BlogPageType, 'tag'>
|
||||
data: BlogTag['pages'][number]['metadata'] & Pick<BlogTag, 'label'>
|
||||
}
|
||||
| {
|
||||
pageType: Extract<BlogPageType, 'archive'>
|
||||
data: {
|
||||
permalink: string
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
import {
|
||||
DocMetadata,
|
||||
LoadedVersion,
|
||||
PluginOptions,
|
||||
} from '@docusaurus/plugin-content-docs'
|
||||
|
||||
export type DocsPageData = {
|
||||
plugin: PluginOptions
|
||||
version: LoadedVersion
|
||||
metadata: DocMetadata
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Props } from '@docusaurus/types'
|
||||
|
||||
// @ts-expect-error
|
||||
import type { SatoriOptions } from 'satori'
|
||||
|
||||
export type ImageGeneratorOptions = SatoriOptions
|
||||
export type ImageGeneratorResult = {
|
||||
path: string
|
||||
absolutePath: string
|
||||
}
|
||||
|
||||
export type ImageRenderer<T = any> = (
|
||||
data: T,
|
||||
context: Props,
|
||||
) =>
|
||||
| [React.ReactNode, ImageGeneratorOptions]
|
||||
| undefined
|
||||
| void
|
||||
| false
|
||||
| Promise<[React.ReactNode, ImageGeneratorOptions] | undefined | void | false>
|
||||
|
||||
export type ImageGenerator<T = any> = (data: T) => string
|
||||
@@ -0,0 +1,5 @@
|
||||
export * from './blog.types'
|
||||
export * from './docs.types'
|
||||
export * from './image.types'
|
||||
export * from './pages.types'
|
||||
export * from './plugin.types'
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Metadata, PluginOptions } from '@docusaurus/plugin-content-pages'
|
||||
|
||||
export type PageData = {
|
||||
metadata: Omit<Metadata, 'title' | 'description'> & {
|
||||
title: string
|
||||
description?: string
|
||||
}
|
||||
plugin: PluginOptions
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { ImageRenderer } from './image.types'
|
||||
|
||||
export type PluginOptions = {
|
||||
path: string
|
||||
imageRenderers: Record<string, ImageRenderer>
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": false,
|
||||
"incremental": true,
|
||||
"tsBuildInfoFile": "./lib/.tsbuildinfo-client",
|
||||
"rootDir": "src",
|
||||
"outDir": "lib",
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"lib": ["DOM"]
|
||||
},
|
||||
"include": ["src/client/**/*", "src/*.d.ts"],
|
||||
"exclude": ["**/__tests__/**"]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": false,
|
||||
"incremental": true,
|
||||
"tsBuildInfoFile": "./lib/.tsbuildinfo",
|
||||
"rootDir": "src",
|
||||
"outDir": "lib",
|
||||
"target": "ES3",
|
||||
"lib": ["DOM"]
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["src/theme", "**/__tests__/**"]
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
// @ts-check
|
||||
|
||||
// Note: type annotations allow type checking and IDEs autocompletion
|
||||
require('dotenv').config()
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user