Releases: FlatbreadLabs/flatbread
🥬 Romaine, Resolvers, Relations, Renovations!
First off, I'd like to extend a warm welcome to our new contributors @odama626 and @Sheharyar566!
This is a mighty large release, JAMpacked with juicy new features and fixes.
🏡 Organization updates
- We created a dedicated @FlatbreadLabs organization which Flatbread now belongs to
- @odama626 is now a co-maintainer of Flatbread & a member of the core team 🙌
- We're working on an official Flatbread docs & marketing site to help others get this bread
- Add badges & Slack link to docs #23
- Dear prospective contributors, we'd love to have ya on the project - join the Slack to get started!
Features
-
Bounded GraphQL server cache #22
-
Recursive directory scan for source-filesystem #25
- Glob matches are supported for content paths to import from nested directories.
{ path: 'content/markdown/posts/**/*.md', collection: 'PostCategoryBlob', refs: { authors: 'Author', }, },
- Named globs will derive meaningful data from a directory name it matches. These are made available as a field on that collection within the GraphQL API:
{ path: 'content/markdown/posts/[category]/[slug].md', collection: 'PostCategory', refs: { authors: 'Author', }, },
- Glob matches are supported for content paths to import from nested directories.
-
Allow field overrides #29
-
Allow multiple transformers #30
- You can now provide an array of transformers to match collections with mixed file types
export default defineConfig({ transformer: [transformerMarkdown(transformerConfig), transformerYaml()], ... }
- You can now provide an array of transformers to match collections with mixed file types
-
Allow serverside function flatbread #31
- Exposes a direct way to resolve GraphQL queries passed to a query function baked with Flatbread schema.
import { FlatbreadProvider } from "@flatbread/core"; // Run Flatbread as a function to execute a subquery const flatbread = new FlatbreadProvider({ // a Flatbread config object here... }); const gqlQuery = ` query Foo { allPosts { id title } } `; const { data } = await flatbread.query({ source: gqlQuery, });
- Exposes a direct way to resolve GraphQL queries passed to a query function baked with Flatbread schema.
-
Introduce concept of custom
resolver
plugins:@flatbread/resolver-svimg
#32- Optimizes images in your data to next-gen formats using src-sets and placeholders
import { createSvImgField } from '@flatbread/resolver-svimg'; export default defineConfig({ ... content: [ { path: 'content/markdown/authors', collection: 'Author', refs: { friend: 'Author', }, overrides: [ createSvImgField('image', { inputDir: 'static/authorImages', outputDir: 'static/g', srcGenerator: (path) => '/g/' + path, }), ], }, ], });
-
Support alternative config file extensions #51
- You should now be able to run Flatbread in any framework and environment, regardless of scope (CJS/ESM).
- Supports the following config flavors:
flatbread.config.js
flatbread.config.mjs
flatbread.config.cjs
flatbread.config.ts
flatbread.config.mts
flatbread.config.cts
Fixes
- Relational/post-resolved filtering via GraphQL subquery #35
- Set up RenovateBot & pin dependencies #44 #46
- Build Flatbread on Windows #85
- Run CI on external PRs #68
⚠️ Breaking changes!
import { filesystem } from ‘flatbread’
is nowimport { sourceFilesystem } from ‘flatbread’
import { markdownTransformer } from ‘flatbread’
is nowimport { transformerMarkdown } from ‘flatbread’
Simplified setup
Introduces improvements to package interdependency ranges.
Previously, a version bump on a package could immediately outdate usage of previous versions of that package in tandem with a peer dependency. Now there are explicit ranges declared which can better follow semvar.
Cleans up the common, default use-case of Flatbread
Now you can import the Markdown Transformer and Source Filesystem from flatbread
directly, instead of installing the plugins as separate. This is still cross-compatible with importing directly from the plugins themselves.
The example below highlights an example config of the typical markdown file flow:
import { defineConfig, markdownTransformer, filesystem } from 'flatbread';
const transformerConfig = {
markdown: {
gfm: true,
externalLinks: true,
},
};
export default defineConfig({
source: filesystem(),
transformer: markdownTransformer(transformerConfig),
content: [
{
path: 'content/posts',
collection: 'Post',
refs: {
authors: 'Author',
},
},
{
path: 'content/authors',
collection: 'Author',
refs: {
friend: 'Author',
},
},
],
});
Node 16
From this point on, I'm only focused on supporting Node LTS which is v16+
Docs
Updated examples, fixed some links, and updated scripts 🫠
Changes to build-in fields
The bread's alive! Having a fun time champagne-testing this in Puerh.wtf's rewrite into SvelteKit x Flatbread 🥳
Feeling incredibly pleased with how freeing & robust Flatbread makes the experience of building a static site fueled by a relational, flat-file data source. I'm enjoying it much more than my experiences with doing the same in Gridsome and Gatsby, so hopefully that means we're onto something!
Now onto the juicy deets...
New features
- We're now releasing under the normal
latest
tag, so all packages can be installed following the pattern ofpnpm i -D <package_name>
without specifying a version. - A new built-in field is made available called
_collection
. This field resolves to the collection name the returned elements belong to, which may not seem useful at the surface but can be powerful for advanced workflows where multiple collections are merged after querying, for example when building a file tree component.
⚠️ Breaking changes!
typeName
has been renamed tocollection
inflatbread.config.js
for thesource-filesystem
plugin- Example of a valid Flatbread config file with this change:
import defineConfig from '@flatbread/config'; import transformer from '@flatbread/transformer-markdown'; import filesystem from '@flatbread/source-filesystem'; const transformerConfig = { markdown: { gfm: true, externalLinks: true, }, }; export default defineConfig({ source: filesystem(), transformer: transformer(transformerConfig), content: [ { path: 'content/markdown/posts', collection: 'Post', // this field used to be called `typeName` refs: { authors: 'Author', }, }, { path: 'content/markdown/authors', collection: 'Author', refs: { friend: 'Author', }, }, ], });
- Fields created by Flatbread have been prefixed with an underscore:
slug
->_slug
filename
->_filename
path
->_path
content
->_content
The Alpha bread
Well here we are. The damn thing kinda really actually works 👁🗨. You can do the core schtick of having markdown files in your repo get automatically converted to a schema consisting of GraphQL typedefs + resolvers that retrieve that data.
That gives a real swell experience. The end user doesn't have to give two shits about what's going on behind the scenes. They can just declare where their data is, the typeName
of it, wait a moment while magic little ferrets and goats rummage around in the console as their server starts alongside their pretty web app, then query the data in those flat file suckers by their id
(obviously way more queries will be added for each content type, but this is the proof of worth moment I've been waiting on for a grand total of 17 short days, so I would say very cool and awesome and dope and sick, in fact) and it shows up on your screen!
Oh I also completely ripped out the GraphQL server in the CLI and slapped in Apollo Server (as pictured above). The CLI itself saw a bunch of tweaks and now the GraphQL server stands alone and does its own Flatbread thing, encapsulating the functions from the core
and config
packages. The CLI is kinda just a pretty scheduler and watcher over the Flatbread/GraphQL server process and your other script.
Bonus point, you can totally roll your own GraphQL server while making use of Flatbread without even touching the flatbread
package. You literally only need these two functions to plug the resultant GraphQL schema into whatever you want:
import {loadConfig} from '@flatbread/config';
import generateSchema from '@flatbread/core';
const config = await loadConfig();
const schema = await generateSchema(config);
...
Take a look at flatbread/src/graphql/server.ts for an example on how to roll your own GQL server & editor.
It doesn't all work yet but it's gettin' there!
The CLI, user config module, filesystem source plugin, and markdown transformer all work!
The playground
shows a proof of concept in its package.json
where you can boot up Flatbread alongside a dev or build process.
Neat CLI stuff
You can pass Flatbread a peer script to run alongside it by separating the two scripts (and their options) with --
:
"scripts": {
"dev": "flatbread start -o -- svelte-kit dev",
"flatbread:help": "flatbread start -h",
"build": "flatbread start -- svelte-kit build",
}
Flatbread captures that second script's options/arguments, automatically detects and uses the package manager you're using (as long as it's pnpm, yarn, or npm), and delays the start of that peer process until Flatbread finishes launching its GraphQL server. This approach cleanly avoids race conditions where your dev server might crank open before Flatbread has had time to parse your content into a schema, etc.
This strategy also allows a nice interface for you to query inside your statically generated apps. You'll get a predictable GraphQL server on a separate process & port from your dev/build process. Flatbread doesn't give a shit what framework you're using. If you can server-side query that endpoint (i.e. http://localhost:5057/graphql
) from within your app ( i.e. http://localhost:3000
), you're off to the races.
No more global vendor lock-in à la Gatsby/Gridsome; bring the tools you want to use.
New Contributors
- @tonyketcham made their first contribution in #3
- @nbennett320 made their first contribution in #2
Full Changelog: https://github.com/tonyketcham/flatbread/commits/v0.0.2