Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(og-gen): Adds package and vite plugin for dynamic og generation #10439

Merged
merged 14 commits into from
Apr 12, 2024
Merged
1 change: 1 addition & 0 deletions .changesets/10439.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- feat(og-gen): Adds package and vite plugin for dynamic og generation (#10439) by @dac09
4 changes: 4 additions & 0 deletions packages/internal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
"files": [
"dist"
],
"exports": {
".": "./dist/index.js",
"./routes": "./dist/routes.js"
dac09 marked this conversation as resolved.
Show resolved Hide resolved
},
"scripts": {
"build": "yarn build:js && yarn build:types",
"build:clean-dist": "rimraf 'dist/**/*/__tests__' --glob",
Expand Down
1 change: 1 addition & 0 deletions packages/og-gen/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!src/__fixtures__/**/dist
3 changes: 3 additions & 0 deletions packages/og-gen/build.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { build } from '@redwoodjs/framework-tools'

await build()
48 changes: 48 additions & 0 deletions packages/og-gen/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "@redwoodjs/og-gen",
"version": "7.0.0",
"type": "module",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: ESM ONLY! ✌️

"repository": {
"type": "git",
"url": "https://github.com/redwoodjs/redwood.git",
"directory": "packages/og-gen"
},
"license": "MIT",
"exports": {
".": {
"default": "./dist/index.js"
},
"./plugin": {
"default": "./dist/vite-plugin-og-gen.js"
}
},
"files": [
"dist"
],
"scripts": {
"build": "tsx ./build.mts && yarn build:types",
"build:pack": "yarn pack -o redwoodjs-og-gen.tgz",
"build:types": "tsc --build --verbose",
"prepublishOnly": "NODE_ENV=production yarn build",
"test": "vitest run",
"test:watch": "vitest watch"
},
"dependencies": {
"@redwoodjs/internal": "workspace:*",
"@redwoodjs/project-config": "workspace:*",
"@redwoodjs/router": "workspace:*",
"@redwoodjs/vite": "workspace:*",
"fast-glob": "3.3.2",
"react": "18.3.0-canary-a870b2d54-20240314",
"react-dom": "18.3.0-canary-a870b2d54-20240314"
},
"devDependencies": {
"@redwoodjs/framework-tools": "workspace:*",
"ts-toolbelt": "9.6.0",
"tsx": "4.7.1",
"typescript": "5.4.3",
"vite": "5.2.8",
"vitest": "1.4.0"
},
"gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1"
}
78 changes: 78 additions & 0 deletions packages/og-gen/src/vite-plugin-og-gen.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { vol, fs as memfs } from 'memfs'
import { describe, expect, test, vi, beforeAll, afterAll } from 'vitest'

import vitePluginOgGen from './vite-plugin-og-gen'

// Memfs mocks the redwood project-config stuff
vi.mock('fs', () => ({ ...memfs, default: { ...memfs } }))
vi.mock('node:fs', () => ({ ...memfs, default: { ...memfs } }))

vi.mock('fast-glob', () => {
return {
default: {
sync: vi
.fn()
.mockReturnValue([
'/redwood-app/web/src/pages/Posts/PostsPage/PostsPage.png.tsx',
'/redwood-app/web/src/pages/About/AboutPage.jpg.jsx',
'/redwood-app/web/src/pages/Contact/ContactPage.png.jsx',
]),
},
}
})

describe('vitePluginOgGen', () => {
let original_RWJS_CWD

beforeAll(() => {
original_RWJS_CWD = process.env.RWJS_CWD
process.env.RWJS_CWD = '/redwood-app'
// Mock the file system using memfs
vol.fromJSON(
{
'redwood.toml': '',
'web/src/pages/Posts/PostsPage/PostsPage.png.tsx': 'PostsOG',
'web/src/pages/About/AboutPage.jpg.jsx': 'AboutOG',
'web/src/pages/Contact/ContactPage.png.jsx': 'ContactOG',
},
'/redwood-app',
)
})

afterAll(() => {
process.env.RWJS_CWD = original_RWJS_CWD
})

test('should generate rollup inputs for all OG components', async () => {
// Type cast so TS doesn't complain calling config below
// because config can be of many types!
const plugin = (await vitePluginOgGen()) as {
config: (...args: any) => any
}

// Call the config function returned by the plugin
const updatedConfig = plugin.config()

// Assert the rollup inputs
expect(updatedConfig.build?.rollupOptions?.input).toEqual({
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll go through this again @cannikin when we pair, so can change things, but just a headsup here on what the output paths will look like

'ogGen/pages/Posts/PostsPage/PostsPage.png':
'/redwood-app/web/src/pages/Posts/PostsPage/PostsPage.png.tsx',
'ogGen/pages/About/AboutPage.jpg':
'/redwood-app/web/src/pages/About/AboutPage.jpg.jsx',
'ogGen/pages/Contact/ContactPage.png':
'/redwood-app/web/src/pages/Contact/ContactPage.png.jsx',
})
})

test('returns the correct Vite plugin object', async () => {
const expectedPlugin = {
name: 'rw-vite-plugin-og-gen',
apply: 'build', // Important!
config: expect.any(Function),
}

const plugin = await vitePluginOgGen()

expect(plugin).toEqual(expectedPlugin)
})
})
51 changes: 51 additions & 0 deletions packages/og-gen/src/vite-plugin-og-gen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import path from 'node:path'

import fg from 'fast-glob'
import type { O } from 'ts-toolbelt'
import type { Plugin as VitePlugin } from 'vite'

import { getPaths } from '@redwoodjs/project-config'

type ConfigPlugin = O.Required<VitePlugin, 'config'>

/**
* This plugin updates the rollup inputs to include all OG components.
*
* Internally, Redwood's vite settings will merge this with the default vite config, and any user config
*/
function vitePluginOgGen(): ConfigPlugin {
const rwPaths = getPaths()

const allOgComponents = fg.sync('pages/**/*.{png,jpg}.{jsx,tsx}', {
cwd: rwPaths.web.src,
absolute: true,
})

// Generates the rollup inputs for all OG components, in their subpaths
// The actual filename doesn't have to match the Page name, just has to be next to the Page
// e.g. { 'ogGen/pages/Posts/PostsPage': '/../pages/Posts/PostsPage/PostsPage.og.png.tsx'}

const ogComponentInput: Record<string, string> = {}
allOgComponents.forEach((ogComponentPath) => {
const pathKey = path
.relative(rwPaths.web.src, ogComponentPath)
.replace(/\.[jt]sx?$/, '')
ogComponentInput[`ogGen/${pathKey}`] = ogComponentPath
})

return {
name: 'rw-vite-plugin-og-gen',
apply: 'build', // We only need to update rollup inputs for build
config: () => {
return {
build: {
rollupOptions: {
input: ogComponentInput,
},
},
}
},
}
}

export default vitePluginOgGen
26 changes: 26 additions & 0 deletions packages/og-gen/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"extends": "../../tsconfig.compilerOption.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"moduleResolution": "Node16", // uses the exports field in @redwoodjs/vite, @redwoodjs/internal
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See this!

"module": "Node16"
},
"include": [
"src"
],
"references": [
{
"path": "../project-config"
},
{
"path": "../vite"
},
{
"path": "../router"
},
{
"path": "../internal"
}
]
}
22 changes: 21 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8540,6 +8540,26 @@ __metadata:
languageName: unknown
linkType: soft

"@redwoodjs/og-gen@workspace:packages/og-gen":
version: 0.0.0-use.local
resolution: "@redwoodjs/og-gen@workspace:packages/og-gen"
dependencies:
"@redwoodjs/framework-tools": "workspace:*"
"@redwoodjs/internal": "workspace:*"
"@redwoodjs/project-config": "workspace:*"
"@redwoodjs/router": "workspace:*"
"@redwoodjs/vite": "workspace:*"
fast-glob: "npm:3.3.2"
react: "npm:18.3.0-canary-a870b2d54-20240314"
react-dom: "npm:18.3.0-canary-a870b2d54-20240314"
ts-toolbelt: "npm:9.6.0"
tsx: "npm:4.7.1"
typescript: "npm:5.4.3"
vite: "npm:5.2.8"
vitest: "npm:1.4.0"
languageName: unknown
linkType: soft

"@redwoodjs/prerender@workspace:*, @redwoodjs/prerender@workspace:packages/prerender":
version: 0.0.0-use.local
resolution: "@redwoodjs/prerender@workspace:packages/prerender"
Expand Down Expand Up @@ -8767,7 +8787,7 @@ __metadata:
languageName: unknown
linkType: soft

"@redwoodjs/vite@workspace:packages/vite":
"@redwoodjs/vite@workspace:*, @redwoodjs/vite@workspace:packages/vite":
version: 0.0.0-use.local
resolution: "@redwoodjs/vite@workspace:packages/vite"
dependencies:
Expand Down
Loading