Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding @gasket/config-plugin #39

Merged
merged 1 commit into from
Aug 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/gasket-config-plugin/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"root": true,
"extends": ["godaddy", "plugin:jest/recommended"]
}
64 changes: 64 additions & 0 deletions packages/gasket-config-plugin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# OSX Finder cache files
.DS_Store

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# Editor files
.idea
71 changes: 71 additions & 0 deletions packages/gasket-config-plugin/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# OSX Finder cache files
.DS_Store

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# Editor files
.idea

### ▲ .gitignore contents above
### ▼ additional ignore files for publishing

test/*
.eslintrc
.gitattributes
17 changes: 17 additions & 0 deletions packages/gasket-config-plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# CHANGELOG

### 1.1.1

- Fix timing bug in relation to `@gasket/redux-plugin`.

### 1.1.0

- Add support for specifying app config in single file.

### 1.0.1

- Move config to preboot phase.

### 1.0.0

- Initial implementation.
21 changes: 21 additions & 0 deletions packages/gasket-config-plugin/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2019 GoDaddy Operating Company, LLC.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
197 changes: 197 additions & 0 deletions packages/gasket-config-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# @gasket/config-plugin

Supports application-specific (non-Gasket) configuration

## What Is This

This plugin:

* Assembles a configuration for your environment from
[config files](#application-config-files)
* [Exposes the configuration](#accessing-config) to server-side code and redux
* Enables plugins to [update the environment's config](#appenvconfig)
* Enables plugins to [inject request-specific configuration](#apprequestconfig)

## Installing

`@gasket/config-plugin` is bundled with `@gasket/default-preset`, so chances
are this is already installed. If you have a custom set of plugins and this
isn't already installed, install with npm or yarn:

```shell
npm install --save @gasket/config-plugin
```

...and add it to your `gasket.config.js`.

```js
module.exports = {
plugins: {
add: ['config']
}
};
```

## Configuring Your Application

By default, this plugin imports files from your `/config` directory to assemble
your application's config. You can change this directory with the `configPath`
option in your `gasket.config.js`:

```js
module.exports = {
configPath: './src/config'
};
```

Gasket first decides which _environment_ you're running in. By default, this
comes from the `NODE_ENV` environment variable or the `--env` command-line
argument. This can also be overridden by the `env` property of
`gasket.config.js`. Environments can be sub-divided (say, for multiple data
centers) through dotted identifiers. Example: `production.v1`.

Once this environment identifier is determined, files are imported based on the
identifier and deep merged together. Files must be CommonJS `.js` modules or
`.json` files with the name of your environment. You may optionally have a
`base.js[on]` file shared across all environments. Given the example
environment `production.v1`, the following files may be merged together:

```
production.v1.js
production.js
base.js
```

If you run your application via `gasket local` or explicitly set your
environment to `local`, there's additional merging behavior:

```
local.overrides.js
local.js
development.js (or dev.js)
base.js
```

The optional `local.overrides.js` is something that can be on individual
workstations and ignored in your `.gitignore`. Depending on if you're naming
your development environment `dev` or `development`, that will automatically
be merged with your `local` configuration.

## Alternative Configuration

Additionally, you can optionally add an `app.config.js` file to the root of
your app's directory, alongside the `gasket.config.js`. This config file allows
you to set up [inline environment overrides], as opposed to in separate files,
following the same rules as the `gasket.config.js`.

If you happen to set up config in both `./config` and `app.config.js`, the
configurations will be merged with `./config` taking priority. The `.json`
extension is also supported for this file.

To support easy local development, you can use an `app.config.local.js`
which will merge in your own local configuration for development. This file
should not be committed, and specified in `.gitignore`.

## Accessing Config

The plugin attaches the configuration from your config files to a `config`
property of the express request object. This makes it accessible to server-side
`getInitialProps` calls:

```jsx harmony
import * as React from 'react';

export default PageComponent extends React.Component {
static getInitialProps({ isServer, req }) {
if (isServer) {
return {
flags: req.config.featureFlags
};
}
}

// ...
}
```

...and custom express middleware (provided you ensure that your middleware
runs _after_ the config plugin). For example, in `/lifecycles/middleware.js`:

```js
module.exports = {
timing: { after: ['config'] },
handler(gasket) {
return (req, res, next) => {
if (req.config.featureFlags.betaSite) {
res.redirect(req.config.betaSiteURL);
} else {
next();
}
}
}
}
```

If you need access to config values in client-side code, this can be done
through your redux store. The config plugin looks for a `redux` property of your
configuration and places it under a `config` property in your initial redux
state.

## Lifecycle Events

### appEnvConfig

The `appEnvConfig` event is fired once the config file contents are normalized.
Hooks are passed the gasket API and the current configuration and should
return a new configuration object with injected modifications. This event will
occur once during startup, and hooks may be asynchronous. Sample:

```js
const fetchRemoteConfig = require('./remote-config');

module.exports = {
hooks: {
async appEnvConfig(gasket, config) {
const remoteCfg = await fetchRemoteConfig();

return {
...config,
...remoteCfg
};
}
}
}
```

### appRequestConfig

On each request, the `appRequestConfig` event is fired, enabling plugins to
inject configuration derived from the request being processed. It is passed
the gasket API, the config, and the Express request & response. Again, hooks
should return a new object instead of mutating an existing object. This is
_especially_ vital in the case of this event to avoid cross-request information
leaks. Sample:

```js
const getFeatureFlags = require('./feature-flags');

module.exports = {
hooks: {
async appRequestConfig(gasket, config, req, res) {

const featureFlags = await getFeatureFlags({
shopperId: req.user.shopperId,
locale: req.cookies.market,
plid: req.user.resellerId
});

return {
...config,
featureFlags
};
}
}
}
```

[inline environment overrides]:https://github.com/godaddy/gasket/docs/blob/master/guides/configuration.md#environments
3 changes: 3 additions & 0 deletions packages/gasket-config-plugin/lib/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
ENV_CONFIG: Symbol()
};
Loading