some progress

This commit is contained in:
Adam Matthiesen 2024-01-26 04:37:17 -08:00
parent ea70d64eb1
commit f3381eb7ba
14 changed files with 287 additions and 82 deletions

View File

@ -6,7 +6,7 @@ import ghostSitemap from "./src/integrations/sitemap";
import ghostRobots from "./src/integrations/robots-txt";
import { loadEnv } from 'vite';
import { fromZodError } from "zod-validation-error";
import { viteGhostCMS } from "./src/virtual";
import { addVirtualImport } from "./src/utils/add-virtual-import";
/** INTERNAL CONSTANTS */
const IC = {
@ -23,7 +23,7 @@ const IC = {
/** INTERNAL STRING */
KEY_MISSING:"CONTENT_API_KEY Missing from .env/environment variables",
/** INTERNAL STRING */
URL_MISSING:"CONTENT_API_URL Missing from .env/environment variables",
URL_MISSING:"CONTENT_API_URL Missing from .env/environment variables or ghostURL under the integration settings in `astro.config.mjs`",
/** INTERNAL STRING */
IT:"Injecting Theme: ",
/** INTERNAL STRING */
@ -55,7 +55,7 @@ const ENV = loadEnv(IC.MODE, process.cwd(), IC.PREFIXES);
* @ For more information and to see the docs check
* @see https://astro-ghostcms.xyz
*/
export default function GhostCMS(options?: UserConfig): AstroIntegration {
export default function GhostCMS(options: UserConfig): AstroIntegration {
return {
name: IC.PKG,
hooks: {
@ -81,6 +81,7 @@ export default function GhostCMS(options?: UserConfig): AstroIntegration {
dCO: GhostConfig.disableConsoleOutput,
SM: GhostConfig.sitemap,
RTXT: GhostConfig.robotstxt,
gSite: GhostConfig.ghostURL
}
// Check For ENV Variables
@ -93,9 +94,11 @@ export default function GhostCMS(options?: UserConfig): AstroIntegration {
}
// CHECK FOR API URL
if(ENV.CONTENT_API_URL === undefined){
if(GCD.gSite === undefined){
logger.error(IC.URL_MISSING);
throw IC.URL_MISSING;
}
}
if(!GCD.dRI){
@ -189,16 +192,17 @@ export default function GhostCMS(options?: UserConfig): AstroIntegration {
// UPDATE ASTRO CONFIG WITH INTEGRATED INTEGRATIONS
integrations: [ ghostSitemap( GCD.SM ), ghostRobots( GCD.RTXT ) ],
// LOAD VITE AND SETUP viteGhostCMS Configs
vite: {
plugins: [
viteGhostCMS( GhostConfig, config )
]
},
}) } catch ( e ) {
logger.error( e as string );
throw e;
};
addVirtualImport({
name: 'virtual:@matthiesenxyz/astro-ghostcms/config',
content: `export default ${ JSON.stringify(GhostUserConfig.data) }`,
updateConfig
})
},
'astro:config:done': async ({ logger }) => {
logger.info(IC.CONFSETUPDONE);

View File

@ -42,7 +42,8 @@
".env.demo",
"index.ts",
"tsconfig.json",
"types.ts"
"types.ts",
"virtual.d.ts"
],
"exports": {
".": "./index.ts",
@ -50,6 +51,7 @@
"./api-core": "./src/api/content-api",
"./404.astro": "./src/default-routes/404/404.astro",
"./rss.xml.ts": "./src/default-routes/rss.xml.ts",
"./config": "./src/integrations/virtual-config.ts",
"./types": "./types.ts"
},
"scripts": {

View File

@ -4,13 +4,17 @@ import { TSGhostContentAPI } from "./content-api";
// LOAD ENVIRONMENT VARIABLES
import { loadEnv } from 'vite';
import config from "../integrations/virtual-config";
const CONF_URL = config.ghostURL;
const {
CONTENT_API_KEY,
CONTENT_API_URL
} = loadEnv('all',process.cwd(),'CONTENT_');
const ghostApiKey = CONTENT_API_KEY;
const ghostUrl = CONTENT_API_URL;
const ghostUrl = CONF_URL?CONF_URL:CONTENT_API_URL;
const version = "v5.0";
const api = new TSGhostContentAPI(ghostUrl, ghostApiKey, version);

View File

@ -3,8 +3,8 @@ import './404.css';
import { getSettings, invariant } from '../../api';
const settings = await getSettings();
invariant(settings, "Settings not found");
---
---
<html lang="en">
<head>
<title>404 | {settings.title}</title>

View File

@ -0,0 +1,6 @@
import config from 'virtual:@matthiesenxyz/astro-ghostcms/config'
import type { GhostUserConfig } from '../schemas'
const UserConfig = config as GhostUserConfig
export default UserConfig;

View File

@ -3,6 +3,16 @@ import { SitemapSchema } from './sitemap';
import { RobotsTxtSchema } from './robots';
export const UserConfigSchema = z.object({
/** OPTIONAL - Either set the URL in your .env or put it here
* @example
* // https://astro.build/config
* export default defineConfig({
* site: "https://demo.astro-ghostcms.xyz/",
* integrations: [ghostcms({
* ghostURL: "https://ghostdemo.matthiesen.xyz"
* })],
* }); */
ghostURL: z.string().optional(),
/** OPTIONAL - Disable Route Injector
* This option allows the user to disable the route injection system and utilize just the integraions other functions. Such as API, sitemap and robotstxt integrations. */
disableRouteInjection: z.boolean().default(false),
@ -23,7 +33,8 @@ export const UserConfigSchema = z.object({
* REFERENCE https://www.npmjs.com/package/astro-robots-txt#configuration
*/
robotstxt: RobotsTxtSchema.optional(),
});
});
/** USER CONFIGURATION SCHEMA */
export type UserConfig = z.infer<typeof UserConfigSchema>
export type GhostUserConfig = z.infer<typeof UserConfigSchema>

View File

@ -0,0 +1,60 @@
import { afterEach, type Mock, describe, expect, test, vi } from "vitest";
import { addVirtualImport } from "./add-virtual-import.js";
import { addVitePlugin } from "./add-vite-plugin.js";
vi.mock('./add-vite-plugin')
const pluginNameStub = <T extends string>(name: T): `vite-plugin-${T}` => `vite-plugin-${name}`
describe("add-virtual-import", () => {
const name = "test-module";
const content = "export default {}";
afterEach(() => {
vi.clearAllMocks();
});
test("It should call `addVitePlugin`", () => {
const updateConfig = vi.fn();
addVirtualImport({
name,
content,
updateConfig,
});
expect(addVitePlugin).toHaveBeenCalled();
});
test("`addVitePlugin` should get called with the correct plugin name", () => {
const updateConfig = vi.fn();
addVirtualImport({
name,
content,
updateConfig,
});
const expectedName = pluginNameStub(name)
const { plugin } = (addVitePlugin as Mock).mock.lastCall[0]
expect(plugin.name).toEqual(expectedName);
});
test("Virtual module should resolve correct name", () => {
const updateConfig = vi.fn();
addVirtualImport({
name,
content,
updateConfig,
});
const { plugin } = (addVitePlugin as Mock).mock.lastCall[0]
const resolvedVirtualModuleId = plugin.resolveId(name)
expect(resolvedVirtualModuleId).toEqual(`\0${ name }`);
});
});

View File

@ -0,0 +1,72 @@
import type { HookParameters } from "astro";
import type { Plugin } from "vite";
import { addVitePlugin } from "./add-vite-plugin.js";
const resolveVirtualModuleId = <T extends string>(id: T): `\0${T}` => {
return `\0${id}`;
};
const createVirtualModule = (name: string, content: string): Plugin => {
const pluginName = `vite-plugin-${name}`;
return {
name: pluginName,
resolveId(id) {
if (id === name) {
return resolveVirtualModuleId(id);
}
},
load(id) {
if (id === resolveVirtualModuleId(name)) {
return content;
}
},
};
};
/**
* Creates a Vite virtual module and updates the Astro config.
* Virtual imports are useful for passing things like config options, or data computed within the integration.
*
* @param {object} params
* @param {string} params.name
* @param {string} params.content
* @param {import("astro").HookParameters<"astro:config:setup">["updateConfig"]} params.updateConfig
*
* @see https://astro-integration-kit.netlify.app/utilities/add-virtual-import/
*
* @example
* ```ts
* // my-integration/index.ts
* import { addVirtualImport } from "astro-integration-kit";
*
* addVirtualImport(
* name: 'virtual:my-integration/config',
* content: `export default ${ JSON.stringify({foo: "bar"}) }`,
* updateConfig
* );
* ```
*
* This is then readable anywhere else in your integration:
*
* ```ts
* // myIntegration/src/component/layout.astro
* import config from "virtual:my-integration/config";
*
* console.log(config.foo) // "bar"
* ```
*/
export const addVirtualImport = ({
name,
content,
updateConfig,
}: {
name: string;
content: string;
updateConfig: HookParameters<"astro:config:setup">["updateConfig"];
}) => {
addVitePlugin({
plugin: createVirtualModule(name, content),
updateConfig,
});
};

View File

@ -0,0 +1,34 @@
import type { HookParameters } from "astro";
import type { PluginOption } from "vite";
/**
* Adds a [vite plugin](https://vitejs.dev/guide/using-plugins) to the
* Astro config.
*
* @param {Params} params
* @param {import("vite").Plugin} params.plugin
* @param {import("astro").HookParameters<"astro:config:setup">["updateConfig"]} params.updateConfig
*
* @see https://astro-integration-kit.netlify.app/utilities/add-vite-plugin/
*
* @example
* ```ts
* addVitePlugin({
* plugin,
* updateConfig
* })
* ```
*/
export const addVitePlugin = ({
plugin,
updateConfig,
}: {
plugin: PluginOption;
updateConfig: HookParameters<"astro:config:setup">["updateConfig"];
}) => {
updateConfig({
vite: {
plugins: [plugin],
},
});
};

View File

@ -1,41 +0,0 @@
import type { AstroConfig, ViteUserConfig } from 'astro'
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import type { UserConfig } from '../schemas';
function resolveVirtualModuleId<T extends string>(id: T): `\0${T}` {
return `\0${id}`
}
export function viteGhostCMS(
opts: UserConfig,
{ root, }: Pick<AstroConfig, 'root' | 'srcDir' | 'trailingSlash'> & {
build: Pick<AstroConfig['build'], 'format'>
}
): NonNullable<ViteUserConfig['plugins']>[number] {
const resolveId = (id: string) =>
JSON.stringify(id.startsWith('.') ? resolve(fileURLToPath(root), id) : id);
const modules = {
'virtual:@matthiesenxyz/astro-ghostcms/config': `export default ${ JSON.stringify(opts) }`
} satisfies Record<string, string>
/** Mapping names prefixed with `\0` to their original form. */
const resolutionMap = Object.fromEntries(
(Object.keys(modules) as (keyof typeof modules)[]).map((key) => [
resolveVirtualModuleId(key),
key,
])
)
return {
name: 'vite-plugin-matthiesenxyz-astro-ghostcms-user-config',
resolveId(id): string | undefined {
if (id in modules) return resolveVirtualModuleId(id)
},
load(id): string | undefined {
const resolution = resolutionMap[id]
if (resolution) return modules[resolution]
},
}
}

View File

@ -6,4 +6,5 @@ export type {
Settings, Tag, TagsIncludeSchema, Tier, TiersIncludeSchema
} from './src/api';
export type { ContentAPICredentials, APIVersions } from "@ts-ghost/core-api";

View File

@ -1,4 +1,4 @@
declare module 'virtual:@matthiesenxyz/astro-ghostcms/config' {
const Config: import('../schemas').UserConfig;
const Config: import('./src/schemas/index').GhostUserConfig;
export default Config;
}

View File

@ -4,5 +4,7 @@ import ghostcms from "@matthiesenxyz/astro-ghostcms";
// https://astro.build/config
export default defineConfig({
site: "https://demo.astro-ghostcms.xyz/",
integrations: [ghostcms()],
integrations: [ ghostcms({
ghostURL: "https://ghostdemo.matthiesen.xyz"
})],
});

View File

@ -24,11 +24,11 @@ importers:
demo:
dependencies:
'@matthiesenxyz/astro-ghostcms':
specifier: 3.1.3
specifier: 3.1.4
version: link:../packages/astro-ghostcms
'@matthiesenxyz/astro-ghostcms-theme-default':
specifier: 0.1.3
version: link:../packages/astro-ghostcms-theme-default
version: 0.1.3(astro@4.2.4)(typescript@5.3.3)
astro:
specifier: ^4.2.4
version: 4.2.4(sass@1.70.0)(typescript@5.3.3)
@ -120,7 +120,7 @@ importers:
version: link:../astro-ghostcms
astro:
specifier: ^4.2.1
version: 4.2.3(typescript@5.3.3)
version: 4.2.3(sass@1.70.0)(typescript@5.3.3)
astro-font:
specifier: ^0.0.77
version: 0.0.77
@ -128,6 +128,9 @@ importers:
'@astrojs/check':
specifier: ^0.4.1
version: 0.4.1(prettier-plugin-astro@0.13.0)(prettier@3.2.4)(typescript@5.3.3)
sass:
specifier: ^1.70.0
version: 1.70.0
typescript:
specifier: ^5.3.3
version: 5.3.3
@ -1405,6 +1408,53 @@ packages:
read-yaml-file: 1.1.0
dev: true
/@matthiesenxyz/astro-ghostcms-theme-default@0.1.3(astro@4.2.4)(typescript@5.3.3):
resolution: {integrity: sha512-ZWo5L5ZSYTWYcQjauDEQBiyH2nqnmoBs8F/cCttRzE6ms5LrWQ65nMuWQQomp5j/kMBBn2upVIi6bEUgoCxt6w==}
peerDependencies:
astro: ^4.2.1
dependencies:
'@matthiesenxyz/astro-ghostcms': 3.1.4(astro@4.2.4)(typescript@5.3.3)
astro: 4.2.4(sass@1.70.0)(typescript@5.3.3)
astro-font: 0.0.77
transitivePeerDependencies:
- '@types/node'
- less
- lightningcss
- sass
- stylus
- sugarss
- supports-color
- terser
- typescript
dev: false
/@matthiesenxyz/astro-ghostcms@3.1.4(astro@4.2.4)(typescript@5.3.3):
resolution: {integrity: sha512-8jXKKG8IhL1M97+p4rjh8gW+6WM0uzQQEA6SARn68HtB3w7rek3rzfnbf/OsXrP9H8LHgYqAUFvZ1AYMWYVnJw==}
peerDependencies:
astro: ^4.2.3
dependencies:
'@astrojs/rss': 4.0.3
'@astrojs/sitemap': 3.0.5
'@matthiesenxyz/astro-ghostcms-theme-default': 0.1.3(astro@4.2.4)(typescript@5.3.3)
'@ts-ghost/core-api': 5.1.2
astro: 4.2.4(sass@1.70.0)(typescript@5.3.3)
astro-robots-txt: 1.0.0
vite: 5.0.12(sass@1.70.0)
vite-tsconfig-paths: 4.3.1(typescript@5.3.3)(vite@5.0.12)
zod: 3.22.4
zod-validation-error: 3.0.0(zod@3.22.4)
transitivePeerDependencies:
- '@types/node'
- less
- lightningcss
- sass
- stylus
- sugarss
- supports-color
- terser
- typescript
dev: false
/@mdx-js/mdx@3.0.0:
resolution: {integrity: sha512-Icm0TBKBLYqroYbNW3BPnzMGn+7mwpQOK310aZ7+fkCtiU3aqv2cdcX+nd0Ydo3wI5Rx8bX2Z2QmGb/XcAClCw==}
dependencies:
@ -2176,7 +2226,7 @@ packages:
zod: 3.22.4
dev: false
/astro@4.2.3(typescript@5.3.3):
/astro@4.2.3(sass@1.70.0)(typescript@5.3.3):
resolution: {integrity: sha512-6bfSogmcwMdaTRAxuhJ7aISGin/T3ovI/69JWPRYOHBkPZxA/EfsNQOI2TiRHFJSF9XtoMnFlgvT+iYapkhOwg==}
engines: {node: '>=18.14.1', npm: '>=6.14.0'}
hasBin: true