Gasket Framework
repository·main·Indexed 40 days ago
https://github.com/godaddy/gasketA robust, pluggable, and render-agnostic framework for rapid delivery of modern JavaScript web applications. Gasket uses a plugin-based architecture to provide commands, lifecycles, and structures for building complex apps, featuring a core lifecycle system (init, configure, prepare, ready) and a CLI for application creation via templates and presets.
What's inside Gasket
- Gasket is a framework maker for JavaScript applications. It allows developers to construct apps and frameworks using various presets and plugins. The core capabilities of a Gasket application—such as specific commands, lifecycles, and data structures—are enabled by the plugins you choose to include in your project.
Key changes in Gasket v7
mainGasket v7 introduces several architectural shifts designed to increase transparency and flexibility:
- Removal of Gasket CLI: Core tasks like transpilation and bundling are now delegated to the primary framework (e.g., Next.js) rather than a dedicated Gasket CLI.
- Lifecycle Simplification: The 'magic files' previously located in the
lifecyclesdirectory have been removed to reduce complexity and increase transparency. - ESM Support: Applications are now fully aligned with ECMAScript Modules (ESM).
- TypeScript Support: Full support for TypeScript is available for both Gasket applications and in-app plugins.
- Next.js 14 Support: Supports both App Router and Page Router, including a custom server option.
- Multiple Instances: Developers can now create multiple Gasket instances within a single application for greater control.
What is Gasket and how does it work?
mainGasket is a tooling ecosystem designed to help developers compose Node.js frameworks by assembling reusable elements into feature-rich applications. Instead of using static starter repos or monolithic generators, Gasket uses a modular approach based on Plugins and Presets.
Core Components:
- CLI: The foundation for generating apps and interacting with them. It provides standard commands like
build,start, andcreate. - Plugins: Composable packages that integrate libraries and provide features. Plugins are not just for scaffolding; they persist in the app to provide runtime functionality. They work by hooking into various Lifecycles.
- Lifecycles: Specific stages of an app's process (e.g., the
createlifecycle) that plugins can hook into to execute logic, install libraries, or generate code. - Presets: A collection of plugins stamped together to form a reusable framework. When you use a preset with the
createcommand, the resulting app is pre-configured with all the features defined by those plugins.
- CLI: The foundation for generating apps and interacting with them. It provides standard commands like
What is Gasket and the API Preset?
mainGasket is a framework maker designed to provide a platform of patterns, integrations, and functionality for building JavaScript web applications and APIs. It uses a plugin architecture where functionality is added via plugins.
Presets are predefined collections of plugins bundled together for specific project types. The Gasket API Preset is specifically designed for creating APIs. It includes plugins for:
- Adding Express to your application.
- Enabling http and https functionality.
- Generating Swagger API documentation.
Access server-side data without Redux using @gasket/data
mainGasket 6 has decoupled from Redux to allow for more flexible state management. The@gasket/datapackage is now the primary way to access server-side data and configurations from the client side without requiring a Redux store. This is supported by the@gasket/nextjspackage, which injects aGasketDatascript into the DOM to make server-side data available to the browser.Understand Gasket lifecycles
mainGasket executes a sequence of lifecycles during instantiation. There are two synchronous lifecycles followed by two asynchronous lifecycles. To ensure the application only proceeds once the instance is fully initialized, wait for the
isReadypromise to resolve.Lifecycle Order
init(Sync): Earliest entry point. Used for setting up initial state.configure(Sync): Allows registered plugins to adjust the configuration object before proceeding.prepare(Async): Used for setup requiring asynchronous operations (e.g., fetching remote config).ready(Async): The final lifecycle. Signals the instance is fully initialized.
Usage Pattern
import gasket from './gasket.js'; gasket.isReady.then(() => { // The instance is now fully initialized gasket.actions.doSomething(); });import gasket from './gasket.js'; gasket.isReady.then(() => { gasket.actions.doSomething(); });Configure tsconfig.server.json for Next.js Custom Servers
mainIf your Next.js app uses
nextServerType: 'customServer'ornextDevProxy: true, the plugin generates atsconfig.server.json. This file provides a separate configuration for server-side TypeScript compilation to distinguish it from client-side bundling.Key characteristics of
tsconfig.server.json:- Module system: Uses
NodeNext(optimized for Node.js runtime) instead ofbundler. - Compilation: Configured to compile to
dist/(enables emission). - Scope: Includes only server files; excludes React components.
- Exclusions: Excludes the Next.js plugin (as the server doesn't use the Next.js bundler) and does not support JSX.
- Module system: Uses
Implement the metadata lifecycle hook
mainPlugins can implement the
metadatalifecycle hook to describe their own metadata and the metadata of their supporting modules. The object returned by this hook will replace the existing metadata for that plugin. This allows plugins to modify their own metadata at runtime.// gasket-plugin-example.js export default { name: 'example', hooks: { /** * @param {Gasket} gasket - The Gasket API * @param {PluginData} data - This plugin's initial metadata * @returns {Object} */ async metadata(gasket, data) { return { ...data, // adding extra data to this plugin's metadata extra: 'information', // add metadata for details of this plugin lifecycles: [{ name: 'some-data', description: 'Allows plugins to do something with data', method: 'exec', parent: 'start' }], // Metadata for these modules will be loaded // Declare as strings or objects with additional data modules: [ { name: 'module-name', version: '7.0.0', description: 'module-name description', link: 'README.md' } ] } }, /** * An example lifecycle hook which utilizes metadata * * @param {Gasket} gasket - The Gasket API */ async example(gasket) { const { metadata } = gasket; if (metadata.plugins.find(pluginData => pluginData.name === 'gasket-plugin-something')) { // only perform some action if a certain plugin is also registered } } } }Customize cache keys with serviceWorkerCacheKey
mainThe
serviceWorkerCacheKeylifecycle hook allows plugins to define how the service worker content is cached. By providing functions that return a string based on thereq(request) andres(response) objects, you can prevent unnecessary recompositions for every unique request. If the generated key matches an existing cache entry, the cached content is returned directly.// Shorthand example: Cache based on a 'market' cookie export default { name: 'sample-plugin', hooks: { serviceWorkerCacheKey: () => (req, res) => req.cookies.market || 'en-US' } }Customize Docusaurus via docusaurus.config.js
mainThe plugin will automatically generate adocusaurus.config.jsfile in your Docusaurus root directory if one does not already exist. You can use this file to apply any standard Docusaurus configuration/customization options directly.Understand @gasket/plugin-typescript lifecycle
mainThe@gasket/plugin-typescriptis a create-time only plugin. It is NOT installed in the final application. Instead, it is used by Gasket presets during thecreate-gasket-appprocess to configure TypeScript, generate necessary configuration files (liketsconfig.json), and set up scripts. Once the application is created, the plugin is discarded.Understand peer dependency version updates
mainIn this monorepo, Changesets automatically updates peer dependency versions from ranges (e.g.,
^7) to specific versions (e.g.,^7.3.5) during the release process. This is a built-in behavior designed to ensure version consistency across the monorepo and cannot be disabled via configuration.Example Behavior: If
@gasket/plugin-loggeris at version7.3.5, a package with the following dependency:"peerDependencies": { "@gasket/plugin-logger": "^7" }will be automatically updated to:
"peerDependencies": { "@gasket/plugin-logger": "^7.3.5" }Workarounds:
- Manual Updates: Revert the peer dependency changes in the generated "Version Packages" PR before merging.
- Post-process Script: Implement a script that runs after
changeset versionto revert the specific version changes.