mirror of
https://github.com/GenderDysphoria/GenderDysphoria.fyi.git
synced 2025-01-31 07:16:17 +00:00
Added support for loading posts
This commit is contained in:
parent
56d5f33453
commit
27621e0edd
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,6 +6,7 @@ node_modules
|
|||||||
/bs-manifest.json
|
/bs-manifest.json
|
||||||
/bs-cache
|
/bs-cache
|
||||||
/pages.json
|
/pages.json
|
||||||
|
/posts.json
|
||||||
/if-*
|
/if-*
|
||||||
/twitter-cache.json
|
/twitter-cache.json
|
||||||
/twitter-config.json
|
/twitter-config.json
|
||||||
|
@ -28,19 +28,19 @@ module.exports = exports = class File {
|
|||||||
file.basename = basename = basename.slice(1);
|
file.basename = basename = basename.slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the public root and any _images segment from the dir
|
|
||||||
const dir = this._dir(file.dir);
|
|
||||||
|
|
||||||
this.kind = kind(filepath);
|
this.kind = kind(filepath);
|
||||||
this.type = type(filepath);
|
this.type = type(filepath);
|
||||||
|
this.input = filepath; // public/file.ext
|
||||||
this.cwd = file.dir;
|
this.cwd = file.dir;
|
||||||
this.ext = this.preprocessed ? file.ext : normalizedExt(file.ext);
|
this.ext = this.preprocessed ? file.ext : normalizedExt(file.ext);
|
||||||
this.input = filepath; // public/file.ext
|
|
||||||
this.base = path.join(...dir); // '', 'folder', 'folder/subfolder'
|
|
||||||
this.dir = path.join('/', ...dir); // /, /folder, /folder/subfolder
|
|
||||||
this.name = name; // index, fileA, fileB
|
this.name = name; // index, fileA, fileB
|
||||||
this.basename = basename; // index.ext, fileA.ext, fileB.ext
|
this.basename = basename; // index.ext, fileA.ext, fileB.ext
|
||||||
this.ext = file.ext;
|
|
||||||
|
const dir = this._dir(file.dir);
|
||||||
|
if (dir) {
|
||||||
|
this.base = path.join(...dir); // '', 'folder', 'folder/subfolder'
|
||||||
|
this.dir = path.join('/', ...dir); // /, /folder, /folder/subfolder
|
||||||
|
}
|
||||||
|
|
||||||
this._out();
|
this._out();
|
||||||
|
|
||||||
|
71
build/files.js
Normal file
71
build/files.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const { groupBy, keyBy, filter, find, get, memoize } = require('lodash');
|
||||||
|
const { kind, KIND } = require('./resolve');
|
||||||
|
const File = require('./file');
|
||||||
|
const Asset = require('./asset');
|
||||||
|
const Page = require('./page');
|
||||||
|
|
||||||
|
module.exports = exports = class Files {
|
||||||
|
|
||||||
|
constructor (paths, base = '') {
|
||||||
|
this.KIND_MAP = this._kindMap();
|
||||||
|
|
||||||
|
this.base = base;
|
||||||
|
this.files = paths.map(this._parsePath.bind(this)).filter(Boolean);
|
||||||
|
|
||||||
|
const {
|
||||||
|
[KIND.PAGE]: pages,
|
||||||
|
[KIND.ASSET]: assets,
|
||||||
|
} = groupBy(this.files, 'kind');
|
||||||
|
|
||||||
|
this.pages = pages || [];
|
||||||
|
this.assets = assets || [];
|
||||||
|
|
||||||
|
this._getTitlecard = memoize(() =>
|
||||||
|
get(find(this.files, { name: 'titlecard', dir: this.base }), [ 0, 'url' ]),
|
||||||
|
);
|
||||||
|
|
||||||
|
this._getWebReady = memoize(() => assets && keyBy(assets.map((a) => a.webready()), 'name'));
|
||||||
|
|
||||||
|
this.for = memoize(this.for);
|
||||||
|
}
|
||||||
|
|
||||||
|
get all () {
|
||||||
|
return this.files;
|
||||||
|
}
|
||||||
|
|
||||||
|
get titlecard () {
|
||||||
|
return this._getTitlecard();
|
||||||
|
}
|
||||||
|
|
||||||
|
get webready () {
|
||||||
|
return this._getWebReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
get tasks () {
|
||||||
|
return this.files.map((a) => a.tasks()).flat(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dir) {
|
||||||
|
dir = path.join(this.base, dir);
|
||||||
|
const subset = filter(this.files, { dir });
|
||||||
|
return new this.constructor(subset, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
_kindMap () {
|
||||||
|
return {
|
||||||
|
[KIND.PAGE]: Page,
|
||||||
|
[KIND.ASSET]: Asset,
|
||||||
|
[KIND.OTHER]: File,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_parsePath (filepath) {
|
||||||
|
if (typeof filepath === 'object') return filepath;
|
||||||
|
const k = kind(filepath);
|
||||||
|
const F = this.KIND_MAP[k];
|
||||||
|
const f = new F(filepath);
|
||||||
|
if (f.kind === KIND.PAGE && f.preprocessed) return false;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
};
|
@ -1,5 +1,8 @@
|
|||||||
|
|
||||||
|
process.env.BLUEBIRD_DEBUG = true;
|
||||||
|
|
||||||
const loadPublicFiles = require('./public');
|
const loadPublicFiles = require('./public');
|
||||||
|
const loadPostFiles = require('./posts');
|
||||||
const Cache = require('./cache');
|
const Cache = require('./cache');
|
||||||
const Promise = require('bluebird');
|
const Promise = require('bluebird');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
@ -16,21 +19,31 @@ const scripts = require('./scripts');
|
|||||||
|
|
||||||
|
|
||||||
exports.everything = function (prod = false) {
|
exports.everything = function (prod = false) {
|
||||||
const fn = async () => {
|
async function fn () {
|
||||||
|
|
||||||
// load a directory scan of the public folder
|
// load a directory scan of the public and post folders
|
||||||
const PublicFiles = await loadPublicFiles();
|
const [ PublicFiles, PostFiles ] = await Promise.all([
|
||||||
|
loadPublicFiles(),
|
||||||
|
loadPostFiles(),
|
||||||
|
]);
|
||||||
|
|
||||||
// load data for all the files in that folder
|
// load data for all the files in that folder
|
||||||
await Promise.map(PublicFiles.assets, (p) => p.load());
|
await Promise.map(PublicFiles.assets, (p) => p.load());
|
||||||
await Promise.map(PublicFiles.pages, (p) => p.load(PublicFiles));
|
await Promise.map(PublicFiles.pages, (p) => p.load(PublicFiles));
|
||||||
|
|
||||||
|
await Promise.map(PostFiles.assets, (p) => p.load());
|
||||||
|
await Promise.map(PostFiles.pages, (p) => p.load(PostFiles));
|
||||||
|
|
||||||
|
|
||||||
// prime tweet data for all pages
|
// prime tweet data for all pages
|
||||||
const pages = await primeTweets(PublicFiles.pages);
|
const pages = await primeTweets(PublicFiles.pages);
|
||||||
|
const posts = await primeTweets(PostFiles.pages);
|
||||||
|
|
||||||
|
|
||||||
// compile all tasks to be completed
|
// compile all tasks to be completed
|
||||||
const tasks = await Promise.all([
|
const tasks = await Promise.all([
|
||||||
PublicFiles.tasks,
|
PublicFiles.tasks,
|
||||||
|
PostFiles.tasks,
|
||||||
scss(prod),
|
scss(prod),
|
||||||
scripts(prod),
|
scripts(prod),
|
||||||
svg(prod),
|
svg(prod),
|
||||||
@ -38,6 +51,7 @@ exports.everything = function (prod = false) {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
await fs.writeFile(resolve('pages.json'), JSON.stringify(pages.map((p) => p.toJson()), null, 2));
|
await fs.writeFile(resolve('pages.json'), JSON.stringify(pages.map((p) => p.toJson()), null, 2));
|
||||||
|
await fs.writeFile(resolve('posts.json'), JSON.stringify(posts.map((p) => p.toJson()), null, 2));
|
||||||
|
|
||||||
await fs.ensureDir(resolve('dist'));
|
await fs.ensureDir(resolve('dist'));
|
||||||
const cache = new Cache({ prod });
|
const cache = new Cache({ prod });
|
||||||
@ -45,10 +59,9 @@ exports.everything = function (prod = false) {
|
|||||||
await evaluate(tasks.flat(), cache);
|
await evaluate(tasks.flat(), cache);
|
||||||
await cache.save();
|
await cache.save();
|
||||||
|
|
||||||
await pageWriter(pages, prod);
|
await pageWriter([ ...pages, ...posts ], prod);
|
||||||
};
|
}
|
||||||
|
|
||||||
const ret = () => fn().catch((err) => { console.log(err.trace || err); throw err; });
|
fn.displayName = prod ? 'buildForProd' : 'build';
|
||||||
ret.displayName = prod ? 'generateEverythingForProd' : 'generateEverything';
|
return fn;
|
||||||
return ret;
|
|
||||||
};
|
};
|
||||||
|
@ -44,7 +44,7 @@ module.exports = exports = async function writePageContent (pages, prod) {
|
|||||||
preview: page.engine === 'md' && String(engines.preview(data.source, data)),
|
preview: page.engine === 'md' && String(engines.preview(data.source, data)),
|
||||||
};
|
};
|
||||||
|
|
||||||
const output = resolve('dist', page.output);
|
const output = resolve('dist', page.out);
|
||||||
await fs.ensureDir(path.dirname(output));
|
await fs.ensureDir(path.dirname(output));
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
fs.writeFile(output, Buffer.from(html)),
|
fs.writeFile(output, Buffer.from(html)),
|
||||||
|
@ -31,23 +31,27 @@ module.exports = exports = class Page extends File {
|
|||||||
'flags',
|
'flags',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.engine = ENGINE[this.type] || ENGINE.COPY;
|
||||||
|
}
|
||||||
|
|
||||||
|
_out () {
|
||||||
var isIndexPage = (this.name === 'index');
|
var isIndexPage = (this.name === 'index');
|
||||||
var isClean = isCleanUrl(this.ext);
|
var isClean = isCleanUrl(this.ext);
|
||||||
|
|
||||||
if (isClean && isIndexPage) {
|
if (isClean && isIndexPage) {
|
||||||
this.output = path.join(this.base, 'index.html');
|
this.out = path.join(this.base, 'index.html');
|
||||||
this.json = path.join(this.base, 'index.json');
|
this.json = path.join(this.base, 'index.json');
|
||||||
this.url = this.dir;
|
this.url = this.dir;
|
||||||
} else if (isClean) {
|
} else if (isClean) {
|
||||||
this.output = path.join(this.base, this.name, 'index.html');
|
this.out = path.join(this.base, this.name, 'index.html');
|
||||||
this.json = path.join(this.base, this.name + '.json');
|
this.json = path.join(this.base, this.name + '.json');
|
||||||
this.url = path.join(this.dir, this.name);
|
this.url = path.join(this.dir, this.name);
|
||||||
} else if (isIndexPage) {
|
} else if (isIndexPage) {
|
||||||
this.output = path.join(this.base, 'index.html');
|
this.out = path.join(this.base, 'index.html');
|
||||||
this.json = path.join(this.base, this.name + '.json');
|
this.json = path.join(this.base, this.name + '.json');
|
||||||
this.url = this.dir;
|
this.url = this.dir;
|
||||||
} else {
|
} else {
|
||||||
this.output = path.join(this.base, this.basename);
|
this.out = path.join(this.base, this.basename);
|
||||||
this.json = path.join(this.base, this.basename + '.json');
|
this.json = path.join(this.base, this.basename + '.json');
|
||||||
this.url = path.join(this.dir, this.basename);
|
this.url = path.join(this.dir, this.basename);
|
||||||
}
|
}
|
||||||
@ -55,8 +59,6 @@ module.exports = exports = class Page extends File {
|
|||||||
const url = new URL(pkg.siteInfo.siteUrl);
|
const url = new URL(pkg.siteInfo.siteUrl);
|
||||||
url.pathname = this.url;
|
url.pathname = this.url;
|
||||||
this.fullurl = url.href;
|
this.fullurl = url.href;
|
||||||
|
|
||||||
this.engine = ENGINE[this.type] || ENGINE.COPY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async load (PublicFiles) {
|
async load (PublicFiles) {
|
||||||
@ -65,8 +67,6 @@ module.exports = exports = class Page extends File {
|
|||||||
fs.stat(this.input).catch(() => ({})),
|
fs.stat(this.input).catch(() => ({})),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const { titlecard, assets } = PublicFiles.for(this.dir);
|
|
||||||
|
|
||||||
// empty file
|
// empty file
|
||||||
if (!raw || !ctime) {
|
if (!raw || !ctime) {
|
||||||
log.error('Could not load page: ' + this.filepath);
|
log.error('Could not load page: ' + this.filepath);
|
||||||
@ -82,20 +82,28 @@ module.exports = exports = class Page extends File {
|
|||||||
|
|
||||||
this.source = body;
|
this.source = body;
|
||||||
this.meta = meta;
|
this.meta = meta;
|
||||||
this.images = assets;
|
|
||||||
this.titlecard = titlecard;
|
|
||||||
this.tweets = (meta.tweets || []).map(parseTweetId);
|
|
||||||
this.dateCreated = meta.date && new Date(meta.date) || ctime;
|
this.dateCreated = meta.date && new Date(meta.date) || ctime;
|
||||||
this.dateModified = mtime;
|
this.dateModified = mtime;
|
||||||
|
|
||||||
this.classes = Array.from(new Set(meta.classes || []));
|
this._parse(PublicFiles);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
_parse (PublicFiles) {
|
||||||
|
const { titlecard, webready } = PublicFiles.for(this.dir);
|
||||||
|
|
||||||
|
this.images = webready;
|
||||||
|
this.titlecard = titlecard;
|
||||||
|
this.tweets = (this.meta.tweets || []).map(parseTweetId);
|
||||||
|
|
||||||
|
this.classes = Array.from(new Set(this.meta.classes || []));
|
||||||
this.flags = this.classes.reduce((res, item) => {
|
this.flags = this.classes.reduce((res, item) => {
|
||||||
var camelCased = item.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
var camelCased = item.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
||||||
res[camelCased] = true;
|
res[camelCased] = true;
|
||||||
return res;
|
return res;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks () {
|
tasks () {
|
||||||
|
16
build/post-asset.js
Normal file
16
build/post-asset.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
const { without } = require('lodash');
|
||||||
|
const Asset = require('./asset');
|
||||||
|
|
||||||
|
const postmatch = /(\d{4}-\d\d-\d\d)\.\d{4}\.(\w+)/;
|
||||||
|
|
||||||
|
module.exports = exports = class PostAsset extends Asset {
|
||||||
|
|
||||||
|
_dir (dir) {
|
||||||
|
dir = dir.replace(postmatch, '$2').split('/');
|
||||||
|
dir = without(dir, 'posts', '_images');
|
||||||
|
dir.unshift('p');
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
54
build/post.js
Normal file
54
build/post.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const { without } = require('lodash');
|
||||||
|
const { resolve, isCleanUrl } = require('./resolve');
|
||||||
|
const Page = require('./page');
|
||||||
|
const pkg = require(resolve('package.json'));
|
||||||
|
|
||||||
|
const postmatch = /(\d{4}-\d\d-\d\d)\.\d{4}\.(\w+)/;
|
||||||
|
|
||||||
|
module.exports = exports = class Post extends Page {
|
||||||
|
|
||||||
|
_dir (dir) {
|
||||||
|
// if the file name matches the postmatch pattern, then this needs to be /p/ file
|
||||||
|
const match = this.name.match(postmatch);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
return [ 'p', match[2] ];
|
||||||
|
}
|
||||||
|
|
||||||
|
dir = dir.replace(postmatch, '$2').split('/');
|
||||||
|
dir = without(dir, 'posts', '_images');
|
||||||
|
dir.unshift('p');
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
_out () {
|
||||||
|
var isIndexPage = (this.name === 'index' || this.name.match(postmatch));
|
||||||
|
var isClean = isCleanUrl(this.ext);
|
||||||
|
|
||||||
|
if (isClean && isIndexPage) {
|
||||||
|
this.out = path.join(this.base, 'index.html');
|
||||||
|
this.json = path.join(this.base, 'index.json');
|
||||||
|
this.url = this.dir;
|
||||||
|
} else if (isClean) {
|
||||||
|
this.out = path.join(this.base, this.name, 'index.html');
|
||||||
|
this.json = path.join(this.base, this.name + '.json');
|
||||||
|
this.url = path.join(this.dir, this.name);
|
||||||
|
} else if (isIndexPage) {
|
||||||
|
this.out = path.join(this.base, 'index.html');
|
||||||
|
this.json = path.join(this.base, this.name + '.json');
|
||||||
|
this.url = this.dir;
|
||||||
|
} else {
|
||||||
|
this.out = path.join(this.base, this.basename);
|
||||||
|
this.json = path.join(this.base, this.basename + '.json');
|
||||||
|
this.url = path.join(this.dir, this.basename);
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = new URL(pkg.siteInfo.siteUrl);
|
||||||
|
url.pathname = this.url;
|
||||||
|
this.fullurl = url.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
21
build/posts.js
Normal file
21
build/posts.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
const glob = require('./lib/glob');
|
||||||
|
const { ROOT, KIND } = require('./resolve');
|
||||||
|
const File = require('./file');
|
||||||
|
const Asset = require('./post-asset');
|
||||||
|
const Post = require('./post');
|
||||||
|
const Files = require('./files');
|
||||||
|
|
||||||
|
class PostFiles extends Files {
|
||||||
|
_kindMap () {
|
||||||
|
return {
|
||||||
|
[KIND.PAGE]: Post,
|
||||||
|
[KIND.ASSET]: Asset,
|
||||||
|
[KIND.OTHER]: File,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = async function loadPublicFiles () {
|
||||||
|
return new PostFiles(await glob('posts/**/*', { cwd: ROOT, nodir: true }));
|
||||||
|
};
|
||||||
|
|
@ -1,64 +1,8 @@
|
|||||||
const glob = require('./lib/glob');
|
const glob = require('./lib/glob');
|
||||||
const { groupBy, keyBy, filter, find, get, memoize } = require('lodash');
|
const { ROOT } = require('./resolve');
|
||||||
const { ROOT, kind, KIND } = require('./resolve');
|
|
||||||
const File = require('./file');
|
|
||||||
const Asset = require('./asset');
|
|
||||||
const Page = require('./page');
|
|
||||||
const Promise = require('bluebird');
|
|
||||||
|
|
||||||
const KIND_MAP = {
|
const Files = require('./files');
|
||||||
[KIND.PAGE]: Page,
|
|
||||||
[KIND.ASSET]: Asset,
|
|
||||||
[KIND.OTHER]: File,
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = exports = async function loadPublicFiles () {
|
module.exports = exports = async function loadPublicFiles () {
|
||||||
const files = await Promise.map(glob('public/**/*', { cwd: ROOT, nodir: true }), (filepath) => {
|
return new Files(await glob('public/**/*', { cwd: ROOT, nodir: true }));
|
||||||
const k = kind(filepath);
|
|
||||||
const F = KIND_MAP[k];
|
|
||||||
const f = new F(filepath);
|
|
||||||
if (f.kind === KIND.PAGE && f.preprocessed) return false;
|
|
||||||
return f;
|
|
||||||
}).filter(Boolean);
|
|
||||||
|
|
||||||
const {
|
|
||||||
[KIND.PAGE]: pages,
|
|
||||||
[KIND.ASSET]: assets,
|
|
||||||
} = groupBy(files, 'kind');
|
|
||||||
|
|
||||||
function within (dir) {
|
|
||||||
const subset = filter(files, { dir });
|
|
||||||
|
|
||||||
const getTitlecard = memoize(() =>
|
|
||||||
get(find(files, { name: 'titlecard' }), [ 0, 'url' ]),
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
|
||||||
[KIND.PAGE]: subpages,
|
|
||||||
[KIND.ASSET]: subassets,
|
|
||||||
} = groupBy(subset, 'kind');
|
|
||||||
|
|
||||||
const webready = subassets && keyBy(subassets.map((a) => a.webready()), 'name');
|
|
||||||
|
|
||||||
return {
|
|
||||||
all: subset,
|
|
||||||
get titlecard () { return getTitlecard; },
|
|
||||||
get pages () {
|
|
||||||
return subpages;
|
|
||||||
},
|
|
||||||
get assets () {
|
|
||||||
return webready;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
all: files,
|
|
||||||
pages,
|
|
||||||
assets,
|
|
||||||
for: memoize(within),
|
|
||||||
get tasks () {
|
|
||||||
return files.map((a) => a.tasks()).flat(1);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user