mirror of
https://github.com/withastro/astro.git
synced 2025-01-20 22:12:38 -05:00
Prevent astro:content from depending on Node builtins (#6537)
* Prevent astro:content from depending on Node builtins * Right file * Move the plugin into test-plugins.js
This commit is contained in:
parent
87d5e96da4
commit
6a7cf0712d
10 changed files with 77 additions and 37 deletions
5
.changeset/four-planets-smoke.md
Normal file
5
.changeset/four-planets-smoke.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Prevent astro:content from depending on Node builtins
|
|
@ -53,6 +53,8 @@
|
||||||
"./assets/services/sharp": "./dist/assets/services/sharp.js",
|
"./assets/services/sharp": "./dist/assets/services/sharp.js",
|
||||||
"./assets/services/squoosh": "./dist/assets/services/squoosh.js",
|
"./assets/services/squoosh": "./dist/assets/services/squoosh.js",
|
||||||
"./content/internal": "./dist/content/internal.js",
|
"./content/internal": "./dist/content/internal.js",
|
||||||
|
"./content/runtime": "./dist/content/runtime.js",
|
||||||
|
"./content/runtime-assets": "./dist/content/runtime-assets.js",
|
||||||
"./debug": "./components/Debug.astro",
|
"./debug": "./components/Debug.astro",
|
||||||
"./internal/*": "./dist/runtime/server/*",
|
"./internal/*": "./dist/runtime/server/*",
|
||||||
"./package.json": "./package.json",
|
"./package.json": "./package.json",
|
||||||
|
|
28
packages/astro/src/content/runtime-assets.ts
Normal file
28
packages/astro/src/content/runtime-assets.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { z } from 'zod';
|
||||||
|
import { imageMetadata, type Metadata } from '../assets/utils/metadata.js';
|
||||||
|
|
||||||
|
export function createImage(options: { assetsDir: string; relAssetsDir: string }) {
|
||||||
|
return () => {
|
||||||
|
if (options.assetsDir === 'undefined') {
|
||||||
|
throw new Error('Enable `experimental.assets` in your Astro config to use image()');
|
||||||
|
}
|
||||||
|
|
||||||
|
return z.string().transform(async (imagePath) => {
|
||||||
|
const fullPath = new URL(imagePath, options.assetsDir);
|
||||||
|
return await getImageMetadata(fullPath);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getImageMetadata(
|
||||||
|
imagePath: URL
|
||||||
|
): Promise<(Metadata & { __astro_asset: true }) | undefined> {
|
||||||
|
const meta = await imageMetadata(imagePath);
|
||||||
|
|
||||||
|
if (!meta) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete meta.orientation;
|
||||||
|
return { ...meta, __astro_asset: true };
|
||||||
|
}
|
|
@ -1,5 +1,3 @@
|
||||||
import { z } from 'zod';
|
|
||||||
import { imageMetadata, type Metadata } from '../assets/utils/metadata.js';
|
|
||||||
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
||||||
import { prependForwardSlash } from '../core/path.js';
|
import { prependForwardSlash } from '../core/path.js';
|
||||||
|
|
||||||
|
@ -199,29 +197,3 @@ async function render({
|
||||||
remarkPluginFrontmatter: mod.frontmatter ?? {},
|
remarkPluginFrontmatter: mod.frontmatter ?? {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createImage(options: { assetsDir: string; relAssetsDir: string }) {
|
|
||||||
return () => {
|
|
||||||
if (options.assetsDir === 'undefined') {
|
|
||||||
throw new Error('Enable `experimental.assets` in your Astro config to use image()');
|
|
||||||
}
|
|
||||||
|
|
||||||
return z.string().transform(async (imagePath) => {
|
|
||||||
const fullPath = new URL(imagePath, options.assetsDir);
|
|
||||||
return await getImageMetadata(fullPath);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getImageMetadata(
|
|
||||||
imagePath: URL
|
|
||||||
): Promise<(Metadata & { __astro_asset: true }) | undefined> {
|
|
||||||
const meta = await imageMetadata(imagePath);
|
|
||||||
|
|
||||||
if (!meta) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete meta.orientation;
|
|
||||||
return { ...meta, __astro_asset: true };
|
|
||||||
}
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import {
|
||||||
|
createImage
|
||||||
|
} from 'astro/content/runtime-assets';
|
||||||
|
|
||||||
|
const assetsDir = '@@ASSETS_DIR@@';
|
||||||
|
|
||||||
|
export const image = createImage({
|
||||||
|
assetsDir,
|
||||||
|
});
|
|
@ -3,8 +3,7 @@ import {
|
||||||
createCollectionToGlobResultMap,
|
createCollectionToGlobResultMap,
|
||||||
createGetCollection,
|
createGetCollection,
|
||||||
createGetEntryBySlug,
|
createGetEntryBySlug,
|
||||||
createImage,
|
} from 'astro/content/runtime';
|
||||||
} from 'astro/content/internal';
|
|
||||||
|
|
||||||
export { z } from 'astro/zod';
|
export { z } from 'astro/zod';
|
||||||
|
|
||||||
|
@ -13,7 +12,6 @@ export function defineCollection(config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const contentDir = '@@CONTENT_DIR@@';
|
const contentDir = '@@CONTENT_DIR@@';
|
||||||
const assetsDir = '@@ASSETS_DIR@@';
|
|
||||||
|
|
||||||
const entryGlob = import.meta.glob('@@ENTRY_GLOB_PATH@@', {
|
const entryGlob = import.meta.glob('@@ENTRY_GLOB_PATH@@', {
|
||||||
query: { astroContent: true },
|
query: { astroContent: true },
|
||||||
|
@ -40,7 +38,3 @@ export const getEntryBySlug = createGetEntryBySlug({
|
||||||
getCollection,
|
getCollection,
|
||||||
collectionToRenderEntryMap,
|
collectionToRenderEntryMap,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const image = createImage({
|
|
||||||
assetsDir,
|
|
||||||
});
|
|
||||||
|
|
|
@ -334,6 +334,7 @@ export type ContentPaths = {
|
||||||
cacheDir: URL;
|
cacheDir: URL;
|
||||||
typesTemplate: URL;
|
typesTemplate: URL;
|
||||||
virtualModTemplate: URL;
|
virtualModTemplate: URL;
|
||||||
|
virtualAssetsModTemplate: URL;
|
||||||
config: {
|
config: {
|
||||||
exists: boolean;
|
exists: boolean;
|
||||||
url: URL;
|
url: URL;
|
||||||
|
@ -352,6 +353,7 @@ export function getContentPaths(
|
||||||
assetsDir: new URL('./assets/', srcDir),
|
assetsDir: new URL('./assets/', srcDir),
|
||||||
typesTemplate: new URL('types.d.ts', templateDir),
|
typesTemplate: new URL('types.d.ts', templateDir),
|
||||||
virtualModTemplate: new URL('virtual-mod.mjs', templateDir),
|
virtualModTemplate: new URL('virtual-mod.mjs', templateDir),
|
||||||
|
virtualAssetsModTemplate: new URL('virtual-mod-assets.mjs', templateDir),
|
||||||
config: configStats,
|
config: configStats,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,11 +36,16 @@ export function astroContentVirtualModPlugin({
|
||||||
const virtualModContents = fsMod
|
const virtualModContents = fsMod
|
||||||
.readFileSync(contentPaths.virtualModTemplate, 'utf-8')
|
.readFileSync(contentPaths.virtualModTemplate, 'utf-8')
|
||||||
.replace('@@CONTENT_DIR@@', relContentDir)
|
.replace('@@CONTENT_DIR@@', relContentDir)
|
||||||
.replace('@@ASSETS_DIR@@', assetsDir)
|
|
||||||
.replace('@@ENTRY_GLOB_PATH@@', entryGlob)
|
.replace('@@ENTRY_GLOB_PATH@@', entryGlob)
|
||||||
.replace('@@RENDER_ENTRY_GLOB_PATH@@', entryGlob);
|
.replace('@@RENDER_ENTRY_GLOB_PATH@@', entryGlob);
|
||||||
|
const virtualAssetsModContents = fsMod
|
||||||
|
.readFileSync(contentPaths.virtualAssetsModTemplate, 'utf-8')
|
||||||
|
.replace('@@ASSETS_DIR@@', assetsDir);
|
||||||
|
|
||||||
const astroContentVirtualModuleId = '\0' + VIRTUAL_MODULE_ID;
|
const astroContentVirtualModuleId = '\0' + VIRTUAL_MODULE_ID;
|
||||||
|
const allContents = settings.config.experimental.assets ?
|
||||||
|
(virtualModContents + virtualAssetsModContents) :
|
||||||
|
virtualModContents;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'astro-content-virtual-mod-plugin',
|
name: 'astro-content-virtual-mod-plugin',
|
||||||
|
@ -53,7 +58,7 @@ export function astroContentVirtualModPlugin({
|
||||||
load(id) {
|
load(id) {
|
||||||
if (id === astroContentVirtualModuleId) {
|
if (id === astroContentVirtualModuleId) {
|
||||||
return {
|
return {
|
||||||
code: virtualModContents,
|
code: allContents,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,7 @@ import * as cheerio from 'cheerio';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { loadFixture } from './test-utils.js';
|
import { loadFixture } from './test-utils.js';
|
||||||
import testAdapter from './test-adapter.js';
|
import testAdapter from './test-adapter.js';
|
||||||
|
import { preventNodeBuiltinDependencyPlugin } from './test-plugins.js';
|
||||||
|
|
||||||
describe('Content Collections', () => {
|
describe('Content Collections', () => {
|
||||||
describe('Query', () => {
|
describe('Query', () => {
|
||||||
|
@ -222,6 +223,11 @@ describe('Content Collections', () => {
|
||||||
root: './fixtures/content-ssr-integration/',
|
root: './fixtures/content-ssr-integration/',
|
||||||
output: 'server',
|
output: 'server',
|
||||||
adapter: testAdapter(),
|
adapter: testAdapter(),
|
||||||
|
vite: {
|
||||||
|
plugins: [
|
||||||
|
preventNodeBuiltinDependencyPlugin()
|
||||||
|
]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
app = await fixture.loadTestAdapterApp();
|
app = await fixture.loadTestAdapterApp();
|
||||||
|
|
17
packages/astro/test/test-plugins.js
Normal file
17
packages/astro/test/test-plugins.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
export function preventNodeBuiltinDependencyPlugin() {
|
||||||
|
// Verifies that `astro:content` does not have a hard dependency on Node builtins.
|
||||||
|
// This is to verify it will run on Cloudflare and Deno
|
||||||
|
return {
|
||||||
|
name: 'verify-no-node-stuff',
|
||||||
|
generateBundle() {
|
||||||
|
const nodeModules = ['node:fs', 'node:url', 'node:worker_threads', 'node:path'];
|
||||||
|
nodeModules.forEach(name => {
|
||||||
|
const mod = this.getModuleInfo(name);
|
||||||
|
if(mod) {
|
||||||
|
throw new Error(`Node builtins snuck in: ${name}`)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue