Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,8 @@ tsconfig.tsbuildinfo
dist/

# Ignore worker artifacts
apps/site/.worker-next
apps/site/.open-next
apps/site/.wrangler

.next.helpers.mjs
.blogData.mjs
7 changes: 4 additions & 3 deletions apps/site/.cloudflare/node/fs.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { files } from '../../next.helpers.mjs';
import { files } from '../../.next.helpers.mjs';

export function readdir(params, cb) {
console.log('fs#readdir', params);
cb(null, []);
}

export function exists(path, cb) {
console.log('fs#exists', path, files.includes(path));
cb(files.includes(path));
const result = files.includes(path) || files.includes(path.replace(/^\//, ''));
console.log('fs#exists', path, result);
cb(result);
}

// export function createReadStream(path) {
Expand Down
4 changes: 4 additions & 0 deletions apps/site/.cloudflare/server-only.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// In our aliased fs code: apps/site/.cloudflare/node/fs/promises.mjs we are importing `getCloudflareContext`
// from `@opennextjs/cloudflare`, this in turn imports from `server-only`, this aliasing maxes it so that
// server-only is not actually removed from the final bundle as it should causing an incorrect server internal
// error, so here we're also mocking out the server-only module as well
21 changes: 11 additions & 10 deletions apps/site/CLOUDFLARE.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,18 @@ You can monitor and configure the project at https://dash.cloudflare.com/fb4a2d0

The following is an incomplete list of tasks and problems that still need to be resolved:

- [ ] update `@opennextjs/cloudflare` to the latest in `/apps/site/package.json`
- [ ] sort out issues with `eval` and MDX and undo edits in `./app/[locale]/[[...path]]/page.tsx`
- [ ] reimplement `getMarkdownFiles` in `next.helpers.mjs` to be generated at build time
- this can be accomplished either via a npm/turbo prebuild task, or possibly as part of next.js SSG/staticProps (but we need to ensure that we don't end up accidentaly downloading this big file to the client as part of hydration)
- [ ] once we have easy access to the list of files, we should roll back changes to `next-data/providers/blogData.ts`
- [ ] back out most changes from `next.dynamic.mjs`
- [ ] instead of using runtime detection via `globalThis.navigator?.userAgent`, we should instead use `alias` feature in `wrangler.toml` to override the implementation of `node:fs` calls but only when running in workerd as we need the build to keep on running in node.js for SSG to work
- [ ] could we reimplement the `existsAsync` call as sync `exists` which consults `getMarkdownFiles` from the task above? alternatively
- [ ] properly implement the rest of `.cloudflare/node/*` polyfills
- [x] update `@opennextjs/cloudflare` to the latest in `/apps/site/package.json`
- [ ] sort out issues with `eval` and MDX (Claudio is looking into this one)
- [ ] and undo edits in `./app/[locale]/[[...path]]/page.tsx`
- [x] reimplement `getMarkdownFiles` in `next.helpers.mjs` to be generated at build time
- this can be accomplished either via a npm/turbo prebuild task, or possibly as part of next.js SSG/staticProps but
- [ ] we need to ensure that we don't end up accidentally downloading this big file to the client as part of hydration
- [x] once we have easy access to the list of files, we should roll back changes to `next-data/providers/blogData.ts`
- [x] back out most changes from `next.dynamic.mjs`
- [x] instead of using runtime detection via `globalThis.navigator?.userAgent`, we should instead use `alias` feature in `wrangler.toml` to override the implementation of `node:fs` calls but only when running in workerd as we need the build to keep on running in node.js for SSG to work
- [x] could we reimplement the `existsAsync` call as sync `exists` which consults `getMarkdownFiles` from the task above?
- [ ] remove symlink hack in `package.json#build:cloudflare`
- would it be possible to make the pages directory part of assets in a less hacky way?
- [ ] move these files under `.worker-next/assets/cdn-cgi/pages` so that these raw md files are not publicly accessible as that could become a maintenance burden down the road.
- [ ] move these files under `.open-next/assets/cdn-cgi/pages` so that these raw md files are not publicly accessible as that could become a maintenance burden down the road.
- [ ] review and improve `/apps/site/turbo.json` changes
- [ ] reenable minification in `next.config.mjs`
11 changes: 10 additions & 1 deletion apps/site/next-data/generators/blogData.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import readline from 'node:readline';

import graymatter from 'gray-matter';

import { getMarkdownFiles } from '../../next.helpers.mjs';
import { getMarkdownFiles } from '../../.next.helpers.mjs';

// gets the current blog path based on local module path
const blogPath = join(process.cwd(), 'pages/en/blog');
Expand Down Expand Up @@ -63,6 +63,15 @@ const generateBlogData = async () => {
'**/index.md',
]);

const result = { /* generated at build time */ };

if (Object.keys(result).length > 0) {
return {
...result,
posts: result.posts.map(post => ({ ...post, date: new Date(post.date) })),
};
}

return new Promise(resolve => {
const posts = [];
const rawFrontmatter = [];
Expand Down
4 changes: 2 additions & 2 deletions apps/site/next-data/providers/blogData.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { cache } from 'react';

// import generateBlogData from '@/next-data/generators/blogData.mjs';
import generateBlogData from '@/.blogData.mjs';
import { BLOG_POSTS_PER_PAGE } from '@/next.constants.mjs';
import type { BlogPostsRSC } from '@/types';

const { categories, posts } = { categories: [], posts: [] };
const { categories, posts } = await generateBlogData();

export const provideBlogCategories = cache(() => categories);

Expand Down
30 changes: 11 additions & 19 deletions apps/site/next.dynamic.mjs
Original file line number Diff line number Diff line change
@@ -1,35 +1,24 @@
'use strict';

import { exists as nodeExists } from 'node:fs';
import { readFile as nodeReadFile } from 'node:fs/promises';
import { exists } from 'node:fs';
import { readFile } from 'node:fs/promises';
import { join, normalize, sep } from 'node:path';

import matter from 'gray-matter';
import { cache } from 'react';
import { VFile } from 'vfile';

import { readFile as runtimeReadFile } from './.cloudflare/node/fs/promises.mjs';
import { exists as runtimeExists } from './.cloudflare/node/fs.mjs';
import { getMarkdownFiles } from './.next.helpers.mjs';
import { BASE_URL, BASE_PATH, IS_DEVELOPMENT } from './next.constants.mjs';
import {
IGNORED_ROUTES,
DYNAMIC_ROUTES,
PAGE_METADATA,
} from './next.dynamic.constants.mjs';
import { getMarkdownFiles } from './next.helpers.mjs';
import { siteConfig } from './next.json.mjs';
import { availableLocaleCodes, defaultLocale } from './next.locales.mjs';
import { compileMDX } from './next.mdx.compiler.mjs';

const readFile =
globalThis.navigator?.userAgent === 'Cloudflare-Workers'
? runtimeReadFile
: nodeReadFile;
const exists =
globalThis.navigator?.userAgent === 'Cloudflare-Workers'
? runtimeExists
: nodeExists;

// This is the combination of the Application Base URL and Base PATH
const baseUrlAndPath = `${BASE_URL}${BASE_PATH}`;

Expand All @@ -50,7 +39,7 @@ const createCachedMarkdownCache = () => {
if (IS_DEVELOPMENT) {
return {
has: () => false,
set: () => {},
set: () => { },
get: () => null,
};
}
Expand Down Expand Up @@ -115,8 +104,10 @@ const getDynamicRouter = async () => {

// This verifies if the given pathname actually exists on our Map
// meaning that the route exists on the website and can be rendered
if (pathnameToFilename.has(normalizedPathname)) {
const filename = pathnameToFilename.get(normalizedPathname);
if (pathnameToFilename.has(normalizedPathname) || pathnameToFilename.has(`pages/${locale}/` + normalizedPathname)) {
const filename = (pathnameToFilename.get(normalizedPathname) ?? pathnameToFilename.get(`pages/${locale}/` + normalizedPathname)).replace(
new RegExp(`^pages/${locale}/`), ''
);

let filePath = join(process.cwd(), 'pages');

Expand All @@ -131,8 +122,9 @@ const getDynamicRouter = async () => {
return { source: fileContent, filename };
}

const existsPromise = path =>
new Promise(resolve => exists(path, resolve));
const existsPromise = path => {
return new Promise(resolve => exists(path, resolve));
}

// No cache hit exists, so we check if the localized file actually
// exists within our file system and if it does we set it on the cache
Expand Down
Loading