Giter Club home page Giter Club logo

fab's Introduction

FAB Stencil Logo Wide

npm Join discussion on Discord GitHub last commit GitHub Workflow Status Financial Contributors on Open Collective

Frontend Application Bundles (πŸ’Ž FABs) are a bundle format for frontend applications.

They unify static sites, single page applications (SPAs), server-side rendering (SSR) & server-side logic in a single format, one that is universally compatible with and easy to deploy to a wide range of hosting providers, even your own infrastructure!

πŸ‘‰ Want to get started? Head to fab.dev/guides/getting-started to start building your own FABs, or read on for more information about the project.

What can I can use FABs for?

Because FABs include server-side JavaScript capabilities but deploy with a single command, you can start to add server-side logic without the complexity of managing servers. Making it easy to do things like:

  • Deploy anything, even a server-rendered NextJS app, to Cloudflare workers.
  • Add server-side logic like redirects & proxying to a Create React App project, without ejecting.
  • Use Gatsby to generate a logged-in vs logged-out homepage and dynamically choose which one to serve to each user.
  • Guard your application against unauthenticated users, by checking a cookie before you serve any JS or HTML.
  • Deploy every commit to a unique URL to share your progress with colleagues.
  • ...and more

πŸ‘‰ These examples will be being fleshed out in the coming days, for now the best place to learn is the Adding Server-Side Logic step of the guide, or join our Discord channel to discuss your use-case.

What frameworks & projects are supported?

At the moment, the FAB project is focussing on supporting the following projects, to try to give the best possible experience for the most users.

πŸ‘‰ If your app is in the following list, npx fab init should be all you need to run to get started!

See fab.dev/guides/getting-started for more info.

  • Client-side rendered React (e.g. Create React App & friends)
  • Server-side, client-side & static pre-rendered NextJS
  • VueJS, AngularJS, Svelte etc projects that compile to static assets
  • Anything else that's fully static (i.e. any app that can be hosted on S3, Netlify, Surge, etc.)
  • An existing server-side rendered applications, with some conversion.

However, any server-side application that runs in (or compiles to) JavaScript, plus any amount of client-side code, should be able to be supported. If your application is not covered by the above list, it's worth reading the FAB project goals and then getting involved to make sure your needs will be supported in future.

Where can I host them?

Currently, we have first-class support for releasing FABs to:

  • Cloudflare Workers, using @fab/deployer-cf-workers
    • Free or $5+/month
    • 200 cities worldwide
    • Extremely high-performance
  • AWS Lambda@Edge, using @fab/deployer-aws-lambda
    • 84 cities worldwide
    • Some [limitations]
    • Good performance
    • Ideal for companies already running infrastructure on AWS
  • Anywhere that can run NodeJS, using @fab/server, e.g.
    • Docker
    • Heroku
    • Now.sh v1

πŸ‘‰ Releases can be triggered manually using fab deploy on the command line or automatically using Linc, a preconfigured CI/CD pipeline from the team behind FABs, with a generous free tier.

See fab.dev/guides/deploying for more info.

How does it work?

A FAB is a special ZIP file with two components, a single server-side JavaScript file, and a folder full of assets.

FAB Structure

From a fully static site, single-page app, to a fully server-rendered JS site, the FAB tooling compiles your application down to these two primitives.

πŸ‘‰ Read more about the FAB structure at fab.dev/kb/fab-structure.

What is a Frontend Application?

The term Frontend Application encompasses a wide range of modern web projects, from purely static sites with no client-side JS, to entirely client-rendered apps hitting an API, or those with a significant server-side-rendering component. But they are defined in opposition to a more traditional "backend" application, which may emit HTML across the wire as well, but usually has a persistent server, with direct connections to databases and a local filesystem.

This is synonymous with some of the more common web app development methodologies in the React/Angular/Vue/Ember ecosystemsβ€”a self-contained single-page-app, potentially pre-rendered or server-rendered, talking to a separate backend app or collection of services via HTTP.

Why a new bundle format?

The Frontend Application Bundle is designed to fill a gap between existing options for frontend application deployment and hosting environments. Usually, you have a choice between a static site host, which prevents you from having any active server-side components, or a more traditional web app host designed for hosting backends.

And while deploying frontend apps to backend-centric hosts works reasonably well, it misses a crucial aspect of frontend web developmentβ€”iteration speed. UI development benefits greatly from rapid prototyping and feedback, and since frontend apps, having no direct dependencies on databases or filesystems, can be cloned & deployed freely, backend-centric workflows can feel overly constrained.

As such, static site hosting has grown in popularity among the frontend application community, and static site generators along with them. But there are many reasons why it's preferable or even essential to include a server-side component in your application, which these projects can't take advantage of without fundamentally changing how they build & deliver their app.

Frontend Application Bundles are the container format that work equally well for fully-static through to full server-rendered frontend apps, meaning you're free to choose your technology independent from your preferred hosting.

Contributors

This project is being led by Glen Maddern, previously a creator of Styled Components & CSS Modules, and supported by the whole team at Linc, which is a pre-configured CI/CD pipeline for sites built with FABs.

Special thanks also must go to:

Code Contributors

Thank you to everyone who has contributed code so far. [Get involved yourself, if you like].

Financial Contributors

Become a financial contributor and help us sustain our community. [Contribute]

Individuals

Organizations

Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]

fab's People

Contributors

bharatramnani94 avatar chiquixote avatar christofferh avatar dependabot-preview[bot] avatar dependabot[bot] avatar dihmeetree avatar evanbb avatar evanderkoogh avatar geelen avatar gregbrimble avatar iand675 avatar itsmatteomanf avatar jahredhope avatar jarvis1010 avatar jesstelford avatar keichinger avatar madebymike avatar monkeywithacupcake avatar plexey avatar rakannimer avatar robertmulders avatar taybenlor avatar thejuan avatar weberjm avatar wizzard0 avatar yacinehmito avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fab's Issues

[@fab/nextjs] should assume `FAB_BUILD` is true

...or something similar. If your next config has something like:

  target: FAB_BUILD ? 'serverless' : 'server',
  assetPrefix: FAB_BUILD ? '/_assets' : '',

and a package.json of this:

"build:fab": "FAB_BUILD=true npm run build && npm run fab:compile",

Then @fab/compile doesn't know you built things correctly. Maybe there should be an assumed env flag, like FAB_BUILD?

Allow build-time ES Modules/TS natively

At the moment, we use Rollup to compile the runtime stage of a plugin, which means we get native ES Modules support, and Typescript annotations stripped. But if you want to use something at build time, we just require it, so it needs to be compatible with whatever version of Node you're running. New node has .mjs support but Typescript is another matter.

I've been trying to get Rollup to compile the runtime entry point (since that's what's going to happen when we produce the FAB), then using node-eval to isntantiate it and call the build method, but it's not been working and I gotta move on to other things. Maybe nobody will hit this issue? I guess we'll find out!

Dev env bugs

A couple of bugs found by @jonatansberg:

it seems that there might be a bug in the deployer-aws-s3 package?
I had to do this in order for the deploys not to crash on me:

  try {
    await createBucket(s3, bucket_name)
    log.tick(`Created bucket πŸ’›${bucket_name}πŸ’› in region πŸ’›${region}πŸ’›.`)
  } catch (e) {}
  • The dev setup expect run-p to be globally available (added it as a dev dependency)
  • Conflicting versions of nanoid (downgrading the s3 package to v2 solved it)

Discussion: Out-of-Band Work

(Not 100% sure this is the right term for this, but the most similar thing I've come across is from Rails land)

I had a thought about a use-case for FABs on Cloudflare, where you could implement a serve-stale behaviour, using the KV store. Let's say you had a slow API that you needed to fetch for a response, but it was ok if the data was very slightly out of date. You could cache the response in the KV store or even use HTTP caching, but when it's stale, you have to choose between two kinda shit options:

  • Wait for the slow API request to finish, meaning that this response takes a while
  • Keep serving the stale content and try to find another way to update the cache

That "other way" could be something like serving the current stale content but also sending a preload header:

Link: <https://myapp.com/api/cache-bust?path=/current/url>; rel=preload; as=fetch

This would cause the browser to ping /api/cache-bust which could be as slow as you like, since the response never gets used.


Alternatively, we could have a dedicated runOutOfBand function that could be returned from a FAB... somehow... so that the FAB runtime could return the response but also kick off some work afterwards, like waiting for the API request to return and updating the cache.

Can the spec expand to handle "code-split" backends?

One of the greatest benefits of using Zeit's infrastructure is that is incredibly simple to have a "code-split" backend.

Meaning you don't have a monolithic server.js, but rather multiple entry points based on the request path.

Benefits are more fault-tolerance, easier scaling, etc. I only see this pattern growing going forward.

Are there any plans on handling this design pattern with fab.dev? The logic to split the backend from an arbitrary server.js is probably impossible...

But seems like it would be possible if the user was required to follow a structure similar to Now/Next.js. Would want to make optional behind a flag for sure.

Or perhaps fab.dev could simply leverage frameworks that already handle this like Next and not try and implement this itself. Would still need to update the spec to support it though.

Thoughts @geelen ?

[plugin-rewire-assets] Immutable asset redirection can be path based

If you have /static/main.a1b2c3d4e5f6.js, we consider that "immutable" since it matches this regexp. So we don't rename/fingerprint it, we just preface the URL with _assets, so it gets stored at _assets/static/main.a1b2c3d4e5f6.js. But we're still adding a reference inside metadata to match it up.

That's got a problem with subsequent FAB builds though, since only the current assets will have rewire rules injected. So old asset URLs will break.

When we get a request for /static/main.a1b2c3d4e5f6.js, one that's not handled by any other plugin, we should assume that it would have been rewired and return a Request as normal. That way the current FAB can happily proxy requests for assets from previous versions.

Break apart `@fab/cli`, then rename the base package to `fab`.

I think npx fab init and yarn dlx fab init could be a good entry point for the whole project, but it downloads all the dependencies every time.

So what I'd like to do is to break @fab/cli into the bare minimum to run fab init and then a dependency similar to @fab/cli (but maybe called something different, cli-actions? fab-cli-build/fab-cli-deploy?). Running fab init will install this, so then all the more hefty commands are available.

[@fab/cli] `fab init` needs to actually prompt, and other improvements

  • fab init -y can't be mandatory, need proper prompting
  • post fab init should give some guidance about this beautiful new world you now have access to.
  • Fab init needs to tell you what's going to happen. Maybe display progress. USE listr.
  • Inject build:fab directly after build in package.json

Lock down whether a "context" argument is needed.

Use cases would be:

β€’ Optional modules (like JS debugging) could be toggled with a server-set context variable. This could be done by Settings, but not clear if it should be.
β€’ Expanded capabilities could be added here, like access to Cloudflare's cache API. Again, this could be supported by a standardised cache object passed down to the FAB, with noop implementations on other runtimes.

[@fab/deployer-aws-lambda] Add invalidaiton paths

At the moment I have hard-coded invalidating the root path / for all deploys to AWS (but allow failures in case your permissions aren't set up right). This should probably be a config property, potentially independent of the actual deployer?

build:fab with nextjs picks up files from previous builds

e.g. after about 10 builds:

      [Compiler] Compiling your server.js:
      [Compiler] Done in 6.07 seconds.
     [Generator] Writing all files to .fab/build
                     /_assets/_next/static/chunks/2d1fb892ad991d9e6642fc990ab158ada56082f7.fe7e92849abaac78ce61.js (30.2 kB)
                     /_assets/_next/static/chunks/513f634b7c7e5d915d97600a8a81692c3da9df9c.fe7e92849abaac78ce61.js (30.2 kB)
                     /_assets/_next/static/chunks/531dc5f5a4410093f1dc92a09e47dea73af36585.fe7e92849abaac78ce61.js (30.2 kB)
                     /_assets/_next/static/chunks/783bb91f701358bec47a1040c6eafd8d7e51e4cc.fe7e92849abaac78ce61.js (30.2 kB)
                     /_assets/_next/static/chunks/78a2496c88cc382763799dbf185d5682b1dbf65f.fe7e92849abaac78ce61.js (30.2 kB)
                     /_assets/_next/static/chunks/b96cc6b703fe46db5f4a742c6d731ad9d791a699.fe7e92849abaac78ce61.js (30.2 kB)
                     /_assets/_next/static/chunks/c739a0c6db9a45acbbebe98df776e6b02d93fcad.fe7e92849abaac78ce61.js (30.2 kB)
                     /_assets/_next/static/chunks/ceff05ded790a38886c393b37ca4584d79a1c787.fe7e92849abaac78ce61.js (30.2 kB)
                     /_assets/_next/static/chunks/eb06a83a524a959639dde6eaffbad9def4218f84.fe7e92849abaac78ce61.js (30.2 kB)
                     /_assets/_next/static/chunks/ed820c581bca6c8030f3f456a1d5fac473a0e2ca.fe7e92849abaac78ce61.js (30.2 kB)
                     /_assets/_next/static/chunks/f409c59c821bd16db9b0be7c42449b69f54e9934.fe7e92849abaac78ce61.js (30.2 kB)
                     /_assets/_next/static/chunks/framework.c6faae2799416a6da8e8.js (129 kB)
                     /_assets/_next/static/runtime/main-17f801b0476b4ad3e2c4.js (16.4 kB)
                     /_assets/_next/static/runtime/main-5d931d17abb85baf99b3.js (16.4 kB)
                     /_assets/_next/static/runtime/polyfills-10c88b4b028d13fe33de.js (80 kB)
                     /_assets/_next/static/runtime/polyfills-e4875719f3b6f90f1438.js (80 kB)
                     /_assets/_next/static/8BO2zwxPDnZBwRdg70Pty/pages/_error.js (9.05 kB)
                     /_assets/_next/static/8BO2zwxPDnZBwRdg70Pty/pages/index.js (24.9 kB)
                     /_assets/_next/static/CweUicyUfvGoRNRkNoAUN/pages/_error.js (9.05 kB)
                     /_assets/_next/static/CweUicyUfvGoRNRkNoAUN/pages/index.js (24.9 kB)
                     /_assets/_next/static/7eJ03MSzPgilZFjy9so9J/pages/_error.js (9.05 kB)
                     /_assets/_next/static/7eJ03MSzPgilZFjy9so9J/pages/index.js (24.9 kB)
                     /_assets/_next/static/IvfdcF82mHvnBRVC83q1Q/pages/_error.js (9.05 kB)
                     /_assets/_next/static/IvfdcF82mHvnBRVC83q1Q/pages/index.js (24.9 kB)
                     /_assets/_next/static/Z_cseBtc3w79X1TD-ijta/pages/_error.js (9.05 kB)
                     /_assets/_next/static/Z_cseBtc3w79X1TD-ijta/pages/index.js (24.9 kB)
                     /_assets/_next/static/cAMH0SIheo_99wn-9GDx2/pages/_error.js (9.05 kB)
                     /_assets/_next/static/cAMH0SIheo_99wn-9GDx2/pages/index.js (24.9 kB)
                     /_assets/_next/static/cHfK3W74z63X84eRk-H-3/pages/_error.js (9.05 kB)
                     /_assets/_next/static/cHfK3W74z63X84eRk-H-3/pages/index.js (24.9 kB)
                     /_assets/_next/static/q2tNryh11FTNMfQcmaf15/pages/_error.js (9.05 kB)
                     /_assets/_next/static/q2tNryh11FTNMfQcmaf15/pages/index.js (24.9 kB)
                     /_assets/_next/static/u2mCnrm14IXkGRKJPCt0G/pages/_error.js (9.05 kB)
                     /_assets/_next/static/u2mCnrm14IXkGRKJPCt0G/pages/index.js (24.9 kB)
                     /_assets/_next/static/v-ndxDmTfxApkt7rTySs1/pages/_error.js (9.05 kB)
                     /_assets/_next/static/v-ndxDmTfxApkt7rTySs1/pages/index.js (24.9 kB)
                     /_assets/_next/static/yaEGPQrfGdEBTL6TwtZVe/pages/_error.js (9.05 kB)
                     /_assets/_next/static/yaEGPQrfGdEBTL6TwtZVe/pages/index.js (24.9 kB)
                     /_assets/favicon.21b739d43.ico (15.1 kB)
                     /server.js (3.13 MB)

this is not a bug per se, it is needed, so that asset deployment is zero-downtime (if half of the assets were served with new version, and half with old); AND this is likely more of a nextjs\webpack issue, but it might make sense to dedup the assets by md5/sha256, and/or keep "last 2-3 versions" in the future

Mailchimp API support

Thanks to @gragland for the use case. Divjoy generates a CRA project with a server with two dependencies: aws-sdk (which works fine) and mailchimp-api-v3, which doesn't.

Two dependencies are the problem:

https://www.npmjs.com/package/request crashes requiring tls
https://www.npmjs.com/package/tar depends on fs

Injecting memfs for fs makes tar compile, but request is a little more difficult.

Feels to me that there might be a library we could find/make that has the same API as request but backs onto fetch instead.

Or, Divjoy could call the Mailchimp API without using the mailchimp-api-v3, since it's only using it in the following lines:

// Add your Mailchimp credentials here
const apiKey = "";
const listId = "";
const mailchimp = new Mailchimp(apiKey);

app.post("/api/newsletter/subscribe", function(req, res) {
  mailchimp
    .request({
      method: "POST",
      path: "/lists/" + listId + "/members",
      body: {
        email_address: req.body.email,
        // Set status to "subscribed" to disable double-opt-in
        status: "pending"
      }
    })
    .then(result => {
      res.send({ status: "success" });
    })
    .catch(err => {
      res.send({ status: "error" });
    });
});

@gragland, thoughts?

Docs feedback

  • What env vars are always set by a FAB build?
  • When do you have to run build:fab, when fab:compile
  • CORS examples

[@fab/deployer-aws-*] Credential Sourcing

AWS SDK already has a pattern for sourcing credentials
https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html

By explicitly forcing users to provide key and secret you break the other flows such as AWS_PROFILE

Work around is to use a thirdparty cli tool for generating temp creds before hand such as https://www.npmjs.com/package/aws-assume for legacy apps

Edit: Get a token invalid error using the above, had to monkey patch

Yarn 2 strict mode support

Fixed a few bugs today, but breaking on upstream dependencies, and I don't know if there's a way around it. PR is open at #131, but this is more of a call for help if someone knows their way around Yarn 2 πŸ™

How about a `zeit/pkg` deployment adapter?

Zeit's pkg project (https://github.com/zeit/pkg) seem to be somewhat similar although with a much more restricted scope.

How about a deployment adapter that uses pkg to build a binary output file?

I like the idea of using FAB to actually build a suite of deliverables.

Much like a graphic designer will deliver an asset in multiple formats and sizes, and electron builds for multiple platforms.

[@fab/deployer-aws-lambda] Origin update?

I followed the guide for deploying to Lambda@Edge
The default CF template has linc specific domains for the origins.
I had assumed the fab deploy would update these to match the deploy settings, but it doesn't seem to.

The static origin should be the s3 bucket?
What's the origin for the renderer?

[@fab/nextjs] Expects static directory in project root where none exists

Following the FAB docs, I configured a new Nextjs 9 project that I generated with create-next-app to output a FAB using version 0.4.0 of @fab/nextjs.

When I ran yarn build:fab, I received the following error message:

[FAB:NextJS] Copying static files
Error: ENOENT: no such file or directory, stat '/home/plexey/work/nextjs9-demo/static'

It appears that @fab/nextjs expects a static directory to exist at the root of your Nextjs project where none exists, at least in the case of a project generated by create-next-app. I think the line in question is here: https://github.com/fab-spec/fab/blob/next/old-packages/fab-nextjs/src/Builder.ts#L45

After adding an empty static directory to the root of my project, @fab/nextjs was then able to successfully compile a FAB. Serving the FAB locally using npx @fab/serve fab.zip also worked successfully.

multiple errors on vanilla create-next-app on Windows

Environment:
Win10 1909, Node v10.15.3, npm 6.13.4, "latest" create-next-app
package.json after running npx fab init:

{
  "name": "nextjs",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "build:fab": "npm run build && npm run fab:build",
    "fab:build": "fab build",
    "fab:serve": "fab serve fab.zip",
    "start": "next start"
  },
  "dependencies": {
    "next": "^9.3.3",
    "react": "^16.13.0",
    "react-dom": "^16.13.0"
  },
  "devDependencies": {
    "@fab/actions": "^0.2.4",
    "@fab/cli": "^0.2.4",
    "@fab/input-nextjs": "^0.2.4",
    "@fab/plugin-render-html": "^0.2.4",
    "@fab/plugin-rewire-assets": "^0.2.4",
    "@fab/server": "^0.2.4"
  }
}

Running npm run build:fab from WSL reports the build as successful

Running from Windows directly reports a ton of messed up paths (I guess path delimiter is hardcoded as "/" somewhere, or "\xxx" gets evaluated as character escapes)

Live dev environment

Was just considering the DX of working on FAB-level plugins after chatting to a few folks this week about the potential for this "FAB server layer" to form a really interesting layer of functionality & caching, between your user & your upstream API server. Starting with this thought bubble, but I realised that the workflow for building this kinda sucks:

Let's say you update one of your FAB plugins, and want to test it:

  • If you're changing your client-side code as well, you need to yarn build:fab to build both your app and the FAB. Even for simple apps, that takes a little while.
  • If you've only changed the FAB server component, yarn fab:build will do it and is fairly quick, but then you do need to rekick your fab serve fab.zip process and refresh the browser.

Was thinking a different workflow, but I wanted to put it out there to see what people thought of it before I lock down an api:

fab dev-server --proxy=3000 --port=3001

This would read your fab.config.json5 file, find all the plugins you're using, ignore (somehow, see below) input-{static,nextjs,sapper}, and things like plugin-rewire-assets, and actually plugin-render-html, since they're really tied to the compiled FAB. But it would live-reload the remaining plugins, and forward requests onto http://localhost:3000.

This should mean you load http://localhost:3001 as if it's your normal dev environment, but requests are moving through the FAB server code, meaning things like /api/graphql could be caught and all their logic iterated on. Hot module loading should still work with Webpack's dev server for client-side changes.

I'd need to stub out the cache module that I'm planning on introducing as part of RC2, which actually gives me a good way to dev on that, so I think this is going to happen.

Plus, I want to run fab.dev/blog as a server-rendered React Notion proxy so I can start to wean myself off gatsby. This would be a good way to test that.

Add typechecking to the rollup build.

At the moment we just strip types during compilation, which is fine because your IDE probably helps you write small plugins that work, but it'd be nice to typecheck TS files as they get rolled up.

I genuinely don't understand Typescript well enought to know how to do that seamlessly, so this is a HELP WANTED issue πŸ™

any hints on manual cf worker deployment?

first, FAB is an awesome idea which bugged me since I heard about CF workers (even before KV/Sites, as you could still package a small website w/routing logic inside the worker body!)

Now, in practice, I'm stuck trying to deploy the FAB I've got :)

I understand the automatic deployer is still in progress, but Workers are mentioned everywhere as the prime target, so I guess it should be possible with a bit of manual work :)

The link to v0 docs gives 'Internal Server Error', unfortunately :( -- #126 I guess
https://fab-docs--production--v0.branch.linc-preview.sh/

So... any hints? Thanks in advance!

[fab init] Handle nextjs exported sites as static

Currently, fab init looks for a next.config.js and a .next directory and assumes that that's a server-rendered NextJS project, then asserts the serverless target in the config.

If a project is using next export, however it needs target: 'server', needs to use @fab/input-static (using the directory name out, for reference) not @fab/input-nextjs, etc.

Need to make fab init aware of this distinction.

For now I've implemented fab init --skip-framework-detection to fall back to the generic static site configurator. We just need to auto-detect something like next export inside the build script and prompt the user to go down this route.

How to debug: "Webpack compiled output headers do not match between page files!"

Hi I've a pretty straight forward nextjs app, some dynamic pages, some static.

I tried to build with Fab following the awesome React Day Berlin talk, but got hit with the following:

[FAB:NextJS] Webpack compiled output headers do not match between page files!

Error: Unexpected compiled page output

Any tips on debugging this ?

Change FabConfig to actually be a Schema

I want some keys to be strings, other regexps. Some keys are required, others are optional. Maybe I can figure out a way to define the whole type tree as a schema to allow non-string leaf nodes, and use that for validation.

Dynamic pages in NextJS return a 404

Buildkite is having an issue with dynamic pages. Those pages work in a local next dev environment, but not when wrapped in fab.

The commit with the first dynamic page is: https://github.com/buildkite/site/pull/573/commits/91385a480eac63699a89f2209bb33dc7cdecc58b

The PR for it is: https://github.com/buildkite/site/pull/573

And as you can see on https://buildkite-site--production--lh-plugin-pages.branch.linc-preview.sh/plugins/buildkite-plugins-docker-compose-buildkite-plugin this return a 404.

Make the config loading module accept any file format within reason.

I don't super want to prescribe JSON5 because it doesn't really affect me, I just like JSON with comments. But you should be able to use whatever you like.

This shouldn't take priority over preserving comments, however, since the whole reason I'm using JSON5 is so that users can have a config file with comments. It's no good if the tooling throws them away when anything changes.

If any file called fab.config.{json,json5,yaml} exists, it should be loaded without needing a flag.

Test that a runtime plugin actually exports `runtime` before passing it on

At the moment, we blindly pass things through to the Rollup compiler, where sometimes things crash with less-than-helpful messages. It'd be nice to do some preparatory work first in the Builder before we pass things on, and maybe pass on the compiled source, rather than just the filename to require.

Optionally use memfs during compilation to speed things up/leave nothing behind.

Previously, it was the job of the framework-specific FAB tool (e.g. @fab/static, @fab/nextjs to generate a .fab/intermediate directory), then the global @fab/compile step would compile that to .fab/build, then zip that into fab.zip.

Give that the compilation step is far less important now (everything meaningful is being moved into a plugin that works on ProtoFab objects), it seems weird to generate a .fab directory at all.

Feels like memfs could be useful here, especially if we're still using Webpack to do the compilation, which, as far as I know, always expects there to be a filesystem.

[@fab/deployer-aws-lambda] Add extra CloudFront config

At the moment, the deployer assumes you're using a CloudFront config similar to https://linc.sh/docs/lambda, so it goes in and updates:

config.DefaultCacheBehavior.LambdaFunctionAssociations = {
  Quantity: 1,
  Items: [
    {
      LambdaFunctionARN,
      EventType: 'origin-request',
    },
  ],
}

That should generally be fine, but something we're not verifying/updating is the other behaviours & origins, for example:

{
  Quantity: 2,
  Items: [
    {
      Id: 'renderer',
      DomainName: 'shared.renderer.linc.sh',
      OriginPath: '',
      CustomHeaders: [Object],
      CustomOriginConfig: [Object]
    },
    {
      Id: 'static-assets',
      DomainName: 'static-assets.linc.sh',
      OriginPath: '/linc-front-end',
      CustomHeaders: { Quantity: 0, Items: [] },
      CustomOriginConfig: {
        HTTPPort: 80,
        HTTPSPort: 443,
        OriginProtocolPolicy: 'https-only',
        OriginSslProtocols: { Quantity: 1, Items: [Array] },
        OriginReadTimeout: 30,
        OriginKeepaliveTimeout: 60
      }
    }
  ]
}

This is the config.DistributionConfig!.Origins object, where the info from the assets_url could be used to verify/override what's there. But then that relies on the following behaviour to be set up:

{
  Quantity: 1,
  Items: [
    {
      PathPattern: '/_assets/*',
      TargetOriginId: 'static-assets',
      ForwardedValues: [Object],
      TrustedSigners: [Object],
      ViewerProtocolPolicy: 'https-only',
      MinTTL: 31536000,
      AllowedMethods: [Object],
      SmoothStreaming: false,
      DefaultTTL: 31536000,
      MaxTTL: 31536000,
      Compress: true,
      LambdaFunctionAssociations: [Object],
      FieldLevelEncryptionId: ''
    }
  ]
}

This is config.DistributionConfig!.CacheBehaviors. I don't want to just blat what's already there, since you might have additional behaviours. But asserting that there definitely is something with PathPattern: '/_assets/*' and TargetOriginId: 'static-assets' seems like a good idea.

Inject commit SHA or bundle ID into FAB, for things like Rollbar

In bitgenics/linc#14 @qnm mentioned he needs a way to set a unique value for Rollup that changes whenever the Javascript source changes.

Right now the work-around is to use the repository tree_id, but that isn't ideal, because now the bundle changes on every repository change, even if that change never got into the bundle.

With a pre-package hook in fab-compile we could do something like calculate a checksum of the client JavaScript assets and set that as a id in the settings.

Handle sites with 17,000 HTML pages

  • Figure out a threshhold where the HTMLs are "too damn big" to fit in the FAB
  • Serialise out the mustache templates into the _assets dir
  • Change the runtime to read the asset, then render like normal.

Big gatsby sites will blow out the FAB, otherwise.

It'd be cool if @fab/serve could optionally run an https server

@fab/serve is great for local verification of @fab/static apps, but sometimes those apps need to run under https (for location/device access, service workers etc.).

Usually browsers make exceptions for those sorts of cases when running on localhost, but you might need to fiddle with settings in dev tools to get everything working.

I've been using a dirty proxy server that passes requests through (or now): https://github.com/colingourlay/fab-serve-https-proxy

Cache headers not being set on AWS

Not sure if I set it up badly, but I'm not getting cache headers on my asset responses

content-encoding: gzip
content-type: application/javascript; charset=utf-8
date: Thu, 21 May 2020 01:20:13 GMT
last-modified: Thu, 21 May 2020 00:17:17 GMT
server: AmazonS3
status: 200
vary: Accept-Encoding
via: 1.1 cc3ab544aae38adfcc35bb790a813e46.cloudfront.net (CloudFront)
x-amz-cf-id: T3zX8wNNw9_T3awgXh7Q2kplZ9bhlhJqjKJIUOwQJpt0Ms8-1E1Ong==
x-amz-cf-pop: SYD4-C2
x-cache: Miss from cloudfront

Can view here https://register.hatch.exchange/?homecompany=domain

@fab/serve blows up on current minimum node.js engine

Support for URL global wasn't added until node.js v10, and this package specifies Node 8 as the minimum engine version.

When I run fab-serve fab.zip or npx @fab/serve fab.zip with node.js v8, I get:

ReferenceError: URL is not defined
    at Server.start (~/.nvm/versions/node/v8.11.4/lib/node_modules/@fab/serve/lib/Server.js:54:18)
    at <anonymous>

Bump dat minimum version to 10 and you're golden πŸ‘Œ

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.