โญโโฎ โญโโฎ
โญโโโโ โฐโโญโโฌโโฎ โฐโโฎโโโโฎ
โ_ โโค <โ โต โ โข โ โข โ
โฐโโโโฐโโดโโฐโโโโฏโโโโฏโโ โฐ
Toolkit for backend application and package development on SEEK's gravel and paved roads:
- Write in TypeScript
- Enforce coding standards with ESLint and Prettier
- Test with Jest
- Deploy with Gantry / Serverless
Related reading:
- SEEK's Technology Strategy
- SEEK's frontend development toolkit, sku
skuba provides you with:
- Commands for developing your project
- Templates to base your backend application on
To create a new project:
npx skuba init
To bootstrap an existing project:
npx skuba configure
skuba supports a global installation to speed up local development:
yarn global add skuba
# Look, no `npx`!
skuba version
skuba commands are typically found in the scripts
section of package.json
.
They replace direct calls to underlying tooling like eslint
and tsc
.
Compile the project.
By convention, this points to a tsconfig.build.json
that excludes tests from your production bundle.
// tsconfig.build.json
{
"exclude": ["**/__mocks__/**/*", "**/*.test.ts", "src/testing/**/*"],
"extends": "tsconfig.json",
"include": ["src/**/*"]
}
// tsconfig.json
{
"compilerOptions": {
"outDir": "lib"
},
"exclude": ["lib*/**/*"]
}
Run skuba configure
if you don't have this file.
Compile the project for compatibility with CommonJS and ES2015 modules.
This is useful for building npm packages, and serves as a replacement for smt build
.
Bootstrap an existing project.
This provides a step-by-step prompt for replacing your config with skuba's.
You should have a clean working tree before running this command,
so it's easy to git reset
in case you want to restore your original config.
Apply automatic fixes to code quality and flag issues that require manual intervention.
This script should be run locally before pushing code to a remote branch.
Option | Description |
---|---|
--debug |
Enable debug console output |
skuba
skuba help
skuba -h
skuba --help
Echoes the available skuba commands.
Create a new project.
This initialises a new directory and Git repository.
skuba supports the following template options:
-
express-rest-api
A REST resource API built on the Express web framework and deployed with Gantry.
-
greeter
A minimal hello world project.
Packs enough Buildkite, Docker and Jest configuration to put you on track for production.
-
koa-rest-api
A REST resource API built on the Koa web framework and deployed with Gantry.
-
lambda-sqs-worker
An asynchronous worker built on AWS Lambda and deployed with Serverless.
Modelled after the "enricher" pattern where an event is received from a source SNS topic and a corresponding enrichment is published to a destination SNS topic. For fault tolerance, a message queue is employed between the source topic and the Lambda function, and unprocessed events are sent to a dead-letter queue for manual triage.
-
lambda-sqs-worker-cdk
An asynchronous worker built on AWS Lambda and deployed with AWS CDK.
SNS -> SQS (with a dead-letter queue) -> Lambda
Comes with configuration validation and infrastructure snapshot testing.
-
oss-npm-package
A public npm package published via semantic-release pipeline.
This is intended for seek-oss projects.
-
private-npm-package
A private npm package published via semantic-release pipeline.
This is intended for SEEK-Jobs projects under the
@seek
npm org. -
github โ
(experimental)BYO starter repo!
skuba will shallow-clone your repo and apply some of its base configuration. You may need to run
skuba configure
after initialisation to fix up inconsistencies.
This script is interactive by default. For unattended execution, pipe in JSON:
skuba init << EOF
{
"destinationDir": "tmp-greeter",
"templateComplete": true,
"templateData": {
"ownerName": "my-org/my-team",
"prodBuildkiteQueueName": "my-team-prod:cicd",
"repoName": "tmp-greeter"
},
"templateName": "greeter"
}
EOF
If you are looking to bootstrap an existing project,
see skuba configure
.
Check for code quality issues.
This script should be run in CI to verify that skuba format
was applied and triaged locally.
Option | Description |
---|---|
--debug |
Enable debug console output |
Run a TypeScript source file, or open a REPL if none is provided:
skuba node src/some-cli-script.ts
skuba node
This automatically registers a src
module alias for ease of local development.
If you use this alias in your production code,
your production entry point(s) will need to import a runtime module alias resolver like skuba-dive/register
.
For example, your src/app.ts
may look like:
// This must be imported directly within the `src` directory
import 'skuba-dive/register';
// You can use the `src` module alias after registration
import { rootLogger } 'src/framework/logging';
Note: if you're using the experimental Babel toolchain, you'll be limited to the fairly primitive
babel-node
REPL. While it can import TypeScript modules, it does not support interactive TypeScript nor modern JavaScript syntax:import { someExport } from 'src/someModule'; // Thrown: [...] Modules aren't supported in the REPL const { someExport } = require('src/someModule'); // Thrown: [...] Only `var` variables are supported in the REPL var { someExport } = require('src/someModule'); // undefined var v: undefined; // Thrown: [...] Unexpected token
Start a live-reloading server for local development.
The entry point is chosen from:
- Command line argument:
skuba start src/app.ts
- Manifest configuration:
package.json#/skuba/entryPoint
- Default:
src/app.ts
The --inspect
and --inspect-brk
Node.js options are supported for debugging sessions.
For example, in Visual Studio Code:
- Run
skuba start --inspect-brk
- Run the built-in
Node.js: Attach
launch configuration
This automatically registers a src
module alias for ease of local development.
If you use this alias in your production code,
your production entry point(s) will need to import a runtime module alias resolver like skuba-dive/register
.
For example, your src/app.ts
may look like:
// This must be imported directly within the `src` directory
import 'skuba-dive/register';
// You can use the `src` module alias after registration
import { rootLogger } 'src/framework/logging';
Your entry point can be a simple module that runs on load:
console.log('Hello world!');
Your entry point can target an exported function:
skuba start --port 12345 src/app.ts#handler
export const handler = async (event: unknown, ctx: unknown) => {
// ...
return;
};
This starts up a local HTTP server that you can POST arguments to:
curl --data '["event", {"awsRequestId": "123"}]' --include localhost:12345
Your entry point should export:
interface Export {
// one of these is required
callback?: () => http.RequestListener;
requestListener?: http.RequestListener;
// optional; falls back to an available port
port?: number;
}
Koa should work with minimal fuss:
const app = new Koa();
// you can also use `export =` syntax as required by koa-cluster
export default Object.assign(app, { port });
As does Express:
const app = express();
export default Object.assign(app, { port });
Run tests with Jest.
Arguments are passed through to the Jest CLI.
skuba version
skuba -v
skuba --version
Echoes the installed version of skuba.
skuba should be a devDependency
that is excluded from your production bundle.
Its Node.js API can be used in build and test code.
Merge additional Jest options into the skuba preset.
This concatenates array options like testPathIgnorePatterns
.
// jest.config.ts
import { Jest } from 'skuba';
export default Jest.mergePreset({
coveragePathIgnorePatterns: ['src/testing'],
setupFiles: ['<rootDir>/jest.setup.ts'],
// this is concatenated to the end of the built-in patterns
testPathIgnorePatterns: ['/test\\.ts'],
});
Wait for a resource to start listening on a socket address.
This can be used to wait for a Docker container to start listening on its port, as described in https://docs.docker.com/compose/startup-order/.
// jest.config.int.js
const rootConfig = require('./jest.config');
module.exports = {
...rootConfig,
globalSetup: '<rootDir>/jest.setup.int.ts',
};
// jest.setup.int.ts
import { Net } from 'skuba';
module.exports = () =>
Net.waitFor({
host: 'composeService',
port: 5432,
resolveCompose: Boolean(process.env.LOCAL),
});
https://github.com/seek-oss/skuba-dive#api-reference
skuba-dive is an optional runtime component for skuba.
skuba-dive should be a dependency
that is included in your production bundle.
skuba tracks technology recommendations from SEEK's Technology Strategy.
skuba bundles developer tooling into one package.json#/devDependency
.
This tooling is managed and upgraded for you. Upgrades are consolidated into one Renovate PR.
TypeScript is proposed as the default language of SEEK.
skuba prescribes TypeScript-focused tooling.
skuba may advocate for certain approaches and technologies through its templates, but this shouldn't be taken as the only way you can write code.
You can continue to base codebases on your own starters and stencils.
skuba distributes a minimal runtime component through the skuba-dive package. It has no aspirations of becoming a monolithic Node.js runtime library.
SEEK's developer community maintains an assortment of targeted packages.
Here are some highlights:
Package | Description |
---|---|
@seek/logger | Write application logs in a standardised format |
seek-datadog-custom-metrics | Write Datadog metrics in Gantry and Lambda |
seek-koala | Add SEEK-standard observability to Koa servers |
๐ @seek/db-client | Connect to databases with credential (rotation) smarts |
๐ @seek/graphql-utils | Add observability to GraphQL servers |
๐ @seek/node-s2sauth-issuer | Call an s2sauth-protected service |
๐ @seek/typegen | Generate TypeScript types from a JSON schema |
๐ @seek/zactive-directory | Authenticate and authorise SSOd users |