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

Docs/issue 430 update technical documentation to reflect current project status #452

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
67 changes: 57 additions & 10 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,53 @@
## Welcome!
We're excited for your interest in Greenwood, and maybe even your contribution!

> _We encourage all contributors to have first read about the project's vision and motivation's on the website's [About page](https://www.greenwoodjs.io/about/). Greenwood is opinionated in the sense that is designed to support development for the web platform and deliver a first class developer experience tailored around that, so that anyone can create a modern and performant website (or webapp, if you prefer). So if that page is the "why", this page is the "how"._

## Technical Design Overview

The Greenwood GitHub repository is a combination [Yarn workspace](https://classic.yarnpkg.com/en/docs/workspaces/) and [Lerna monorepo](https://github.com/lerna/lerna). The root level _package.json_ defines the workspaces and shared tooling used throughout the project, like for linting, testing, etc.

The two main directories are:
- [_packages/_](https://github.com/ProjectEvergreen/greenwood/tree/master/packages) - Packages published to NPM under the `@greenwood/` scope
- [_www/_](https://github.com/ProjectEvergreen/greenwood/tree/master/www) - [website](https://www.greenwoodjs.io) / documentation code


> _This guide is mainly intended to walk through the **cli** package, it being the principal pacakge within the project supporting all other packages._

### CLI

The CLI is the main entry point for Greenwood, similar to how the [front-controller pattern](https://en.wikipedia.org/wiki/Front_controller) works. When users run a command like `greenwood build`, they are effectively invoking the file _src/index.js_ within the `@greenwood/cli` package.

At a high level, this is how a command goes through the CLI:
1. Each documented command a user can run maps to a script in the _commands/_ directory.
1. Each command can invoke any number of lifecycles from the _lifecycles/_ directory.
1. Lifecycles capture specific steps needed to build a site, serve it, generate a content dependency graph, etc.


### Layout
The [layout](https://github.com/ProjectEvergreen/greenwood/tree/master/packages/cli/src) of the CLI package is as follows:

- _index.js_ - Front controller
- _commands/_ - map to runnable userland commands
- _config/_ - Tooling configuration that Greenwood creates
- _data/_ - Custom GraphQL server and client side utilities
- _lib/_ - Customfized Local third party libraries and utility files
- _lifecycles/_ - Tasks that can be composed by commands to support the full needs of that command
- _plugins/_ - Custom defaukt plugins maintained by the CLI project
- _templates/_ - Default templates and / or pages provided by Grennwood.

We'll focus on the most important two here:


### Lifecycles
Aside from the config and graph lifecycles, all lifecycles (and config files and plugins) typically expect a compilation object to be passed in.

Lifeycles include handling:
- starting a production or development server for a compilation
- optimizing a compilation for production
- prerendering a compilation for production
- fetching external (content) data sources


## Issues
Please make sure to have the following prepared (where applicable)
Expand All @@ -14,8 +61,8 @@ Please make sure to have the following prepared (where applicable)

## Pull Requests
Pull requests are the best! To best help facililate contributions to the project, here are some requests:
- We generally we prefer an issue be opened first, to help faciliate general discussion outside of the code review process itself and align on the ask and any expections. However, for typos in docs and minor "chore" like tasks a PR is usually sufficient. When in doubt, open an issue.
- For bugs, please consider reviewing the issue tracker.
- We generally prefer an issue be opened first, to help faciliate general discussion outside of the code review process itself and align on the ask and any expections. However, for typos in docs and minor "chore" like tasks a PR is usually sufficient. When in doubt, open an issue.
- For bugs, please consider reviewing the issue tracker first.
- For branching, we generally follow the convention `<issue-label>/issue-<number>-<issue-title>`, e.g. _bug/issue-12-fixed-bug-with-yada-yada-yada_
- To test the CI build scripts locally, run the `yarn` commands mentioned in the below section on CI.

Expand All @@ -31,21 +78,21 @@ A preview is also made available within the status checks section of the PR in G

## Local Development
To develop for the project, you'll want to follow these steps:
1. Have [NodeJS LTS](https://nodejs.org) installed (>= 10.x) and [Yarn](https://yarnpkg.com/)
1. Have [NodeJS LTS](https://nodejs.org) installed (>= 12.x) and [Yarn](https://yarnpkg.com/)
1. Clone the repository
1. Run `yarn install`
1. Run `yarn lerna bootstrap`

### Tasks
The Greenwood website is currently built by Greenwood itself, and all files for it are located in this repository in the _www/_ directory. In addition to unit tests, you will want to verify all changes by running the website locally.
### Scripts
The [Greenwood website](https://www.greenwoodjs.io/) is currently built by Greenwood, and all files for it are located in this repository under the [_www/_ directory](https://github.com/ProjectEvergreen/greenwood/tree/master/www) workspace. In addition to unit tests, you will want to verify any changes by running the website locally.

Below are the development tasks available for working on this project:
- `yarn develop` - Develop for the website locally using the dev server at `localhost:1984` in your browser.
- `yarn build` - Builds the website for production.
- `yarn serve` - Builds the website for production and runs it on a local webserver at `localhost:8000`

### Packages
Greenwood is organized into packages as a monorepo, managed by [Lerna](https://lerna.js.org/) and [Yarn Workspaces](https://yarnpkg.com/lang/en/docs/workspaces/). You can find all of these in the _packages/_ directory. Each package will manage its own:
As mentioned above, Greenwood is organized into packages as a monorepo, managed by [Lerna](https://lerna.js.org/) and [Yarn Workspaces](https://yarnpkg.com/lang/en/docs/workspaces/). You can find all of these in the _packages/_ directory. Each package will manage its own:
- Dependencies
- README
- Test Cases
Expand All @@ -65,7 +112,7 @@ Yarn workspaces will automatically handle installing _node_modules_ in the appro


## Unit Testing
[TDD](https://en.wikipedia.org/wiki/Test-driven_development) is the recommended approach for developing for Greenwood and for the style of test writing we use [BDD style testing](https://en.wikipedia.org/wiki/Behavior-driven_development); "cases". Cases are used to capture the various configurations and expected outputs of Greenwood when running its commands, in a way that is closer to how a user would be expecting Greenwood to work.
[TDD](https://en.wikipedia.org/wiki/Test-driven_development) is the recommended approach for developing for Greenwood and for the style of test writing we use [BDD style testing](https://en.wikipedia.org/wiki/Behavior-driven_development); "cases". Cases are used to capture the various configurations and expected outputs of Gre enwood when running its commands, in a way that is closer to how a user would be expecting Greenwood to work.

### Running Tests
To run tests in watch mode, use:
Expand All @@ -87,15 +134,15 @@ Below are some tips to help with running / debugging tests:
> **PLEASE DO NOT COMMIT ANY OF THESE ABOVE CHANGES THOUGH**

### Writing Tests
Cases follow a convention starting with the command (e.g. `build`) and and the capability and features being tested, like configuration with a particular option (e.g. `publicPath`):
Cases follow a convention starting with the command (e.g. `build`) and and the capability and features being tested, like configuration with a particular option (e.g. `port`):
```shell
<command>.<capability>.<feature>.spec.js
```

Examples:
- _build.default.spec.js_ - Would test `greenwood build` with no config and no workspace.
- _build.config.workspace-custom.spec.js_ - Would test `greenwood build` with a config that had a custom `workspace`
- _build.config.workspace-public-path.spec.js_ - Would test `greenwood build` with a config that had a custom `workspace` and `publicPath` set.
- _build.config.workspace-dev-server-port.spec.js_ - Would test `greenwood build` with a config that had a custom `workspace` and `devServer.port` set.

### Notes
Here are some thigns to keep in mind while writing your tests, due to the asynchronous nature of Greenwwood:
Expand All @@ -104,7 +151,7 @@ Here are some thigns to keep in mind while writing your tests, due to the asynch
- Avoid arrow functions in mocha tests (e.g. `() => `) as this [can cause unexpected behaviors.](https://mochajs.org/#arrow-functions). Just use `function` instead.

## Internet Explorer
For situations that require testing Internet Explorer or Edge browser, Microsoft [provides Virtual Machines](https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/) for various combinations of Windows and Internet Explorer versions. [VirtualBox](https://www.virtualbox.org/) is a good platform to use for these VMs.
For situations that require testing Internet Explorer or Edge browser, Microsoft provides [Virtual Machines](https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/) for various combinations of Windows and Internet Explorer versions. [VirtualBox](https://www.virtualbox.org/) is a good platform to use for these VMs.

To test from a VM, you can
1. Run `yarn serve`
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/develop.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = runDevServer = async () => {
const { userWorkspace } = compilation.context;

devServer(compilation).listen(port, () => {
console.info(`Started local development at localhost:${port}`);
console.info(`Started local development server at localhost:${port}`);
const liveReloadServer = livereload.createServer({
exts: ['html', 'css', 'js', 'md'],
applyCSSLive: false // https://github.com/napcs/node-livereload/issues/33#issuecomment-693707006
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/commands/eject.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module.exports = ejectConfigFiles = async (copyAllFiles) => {
if (copyAllFiles) {
configFilePaths = fs.readdirSync(path.join(__dirname, '../config'));
} else {
// TODO
configFilePaths = [
'webpack.config.common.js',
'webpack.config.develop.js',
Expand Down
4 changes: 1 addition & 3 deletions packages/cli/src/data/queries/config.gql
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
query {
config {
devServer {
port,
host
port
},
meta {
name,
Expand All @@ -13,7 +12,6 @@ query {
href
},
optimization,
publicPath,
title,
workspace
}
Expand Down
4 changes: 1 addition & 3 deletions packages/cli/src/data/schema/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ const getConfiguration = async (root, query, context) => {
// https://www.greenwoodjs.io/docs/configuration
const configTypeDefs = gql`
type DevServer {
port: Int,
host: String
port: Int
}

type Meta {
Expand All @@ -24,7 +23,6 @@ const configTypeDefs = gql`
devServer: DevServer,
meta: [Meta],
optimization: String,
publicPath: String,
title: String,
workspace: String
}
Expand Down
27 changes: 2 additions & 25 deletions packages/cli/src/lifecycles/config.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
const fs = require('fs');
const path = require('path');
const url = require('url');

// TODO const optimizations = ['strict', 'spa'];

let defaultConfig = {
workspace: path.join(process.cwd(), 'src'),
devServer: {
port: 1984,
host: 'localhost'
port: 1984
},
// TODO optimization: 'spa',
publicPath: '/',
title: 'My App',
meta: [],
plugins: [],
Expand All @@ -27,7 +23,7 @@ module.exports = readAndMergeConfig = async() => {

if (fs.existsSync(path.join(process.cwd(), 'greenwood.config.js'))) {
const userCfgFile = require(path.join(process.cwd(), 'greenwood.config.js'));
const { workspace, devServer, publicPath, title, markdown, meta } = userCfgFile;
const { workspace, devServer, title, markdown, meta } = userCfgFile;

// workspace validation
if (workspace) {
Expand Down Expand Up @@ -61,15 +57,6 @@ module.exports = readAndMergeConfig = async() => {
customConfig.title = title;
}

if (publicPath) {
if (typeof publicPath !== 'string') {
reject('Error: greenwood.config.js publicPath must be a string');
} else {
customConfig.publicPath = publicPath;
// console.log('custom publicPath provided => ', customConfig.publicPath);
}
}

if (meta && meta.length > 0) {
customConfig.meta = meta;
}
Expand Down Expand Up @@ -102,16 +89,6 @@ module.exports = readAndMergeConfig = async() => {

if (devServer && Object.keys(devServer).length > 0) {

if (devServer.host) {
// eslint-disable-next-line max-depth
if (url.parse(devServer.host).pathname === null) {
reject(`Error: greenwood.config.js devServer host type must be a valid pathname. Passed value was: ${devServer.host}`);
} else {
customConfig.devServer.host = devServer.host;
// console.log(`custom host provided => ${customConfig.devServer.host}`);
}
}

if (devServer.port) {
// eslint-disable-next-line max-depth
if (!Number.isInteger(devServer.port)) {
Expand Down
59 changes: 0 additions & 59 deletions packages/cli/src/lifecycles/context.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
const fs = require('fs');
const path = require('path');
// const defaultTemplatesDir = path.join(__dirname, '../templates/');
// const defaultConfigDir = path.join(__dirname, '../config');
const scratchDir = path.join(process.cwd(), './.greenwood/');
const outputDir = path.join(process.cwd(), './public');
const dataDir = path.join(__dirname, '../data');
Expand All @@ -11,63 +9,6 @@ module.exports = initContexts = async({ config }) => {
return new Promise(async (resolve, reject) => {

try {
// TODO
// const userAppTemplate = path.join(userTemplatesDir, 'app-template.js');
// const userPageTemplate = path.join(userTemplatesDir, 'page-template.js');
// const indexPageTemplate = 'index.html';
// const notFoundPageTemplate = '404.html';
// const webpackProd = 'webpack.config.prod.js';
// const webpackDev = 'webpack.config.develop.js';
// const babelConfig = 'babel.config.js';
// const postcssConfig = 'postcss.config.js';

// const userHasWorkspace = await fs.exists(userWorkspace);
// const userHasWorkspacePages = await fs.exists(userPagesDir);
// const userHasWorkspaceTemplates = await fs.exists(userTemplatesDir);
// const userHasWorkspacePageTemplate = await fs.exists(userPageTemplate);
// const userHasWorkspaceAppTemplate = await fs.exists(userAppTemplate);
// const userHasWorkspaceIndexTemplate = await fs.exists(path.join(userTemplatesDir, 'index.html'));
// const userHasWorkspaceNotFoundTemplate = await fs.exists(path.join(userTemplatesDir, '404.html'));
// const userHasWorkspaceWebpackProd = await fs.exists(path.join(process.cwd(), webpackProd));
// const userHasWorkspaceWebpackDevelop = await fs.exists(path.join(process.cwd(), webpackDev));
// const userHasWorkspaceBabel = await fs.exists(path.join(process.cwd(), babelConfig));
// const userHasWorkspacePostCSS = await fs.exists(path.join(process.cwd(), postcssConfig));

// let context = {
// dataDir,
// scratchDir,
// publicDir,
// pagesDir: userHasWorkspacePages ? userPagesDir : defaultTemplatesDir,
// templatesDir: userHasWorkspaceTemplates ? userTemplatesDir : defaultTemplatesDir,
// userWorkspace: userHasWorkspace ? userWorkspace : defaultTemplatesDir,
// pageTemplatePath: userHasWorkspacePageTemplate
// ? userPageTemplate
// : path.join(defaultTemplatesDir, 'page-template.js'),
// appTemplatePath: userHasWorkspaceAppTemplate
// ? userAppTemplate
// : path.join(defaultTemplatesDir, 'app-template.js'),
// indexPageTemplatePath: userHasWorkspaceIndexTemplate
// ? path.join(userTemplatesDir, indexPageTemplate)
// : path.join(defaultTemplatesDir, indexPageTemplate),
// notFoundPageTemplatePath: userHasWorkspaceNotFoundTemplate
// ? path.join(userTemplatesDir, notFoundPageTemplate)
// : path.join(defaultTemplatesDir, notFoundPageTemplate),
// indexPageTemplate,
// notFoundPageTemplate,
// assetDir: path.join(userHasWorkspace ? userWorkspace : defaultTemplatesDir, 'assets'),
// webpackProd: userHasWorkspaceWebpackProd
// ? path.join(process.cwd(), './', webpackProd)
// : path.join(defaultConfigDir, webpackProd),
// webpackDevelop: userHasWorkspaceWebpackDevelop
// ? path.join(process.cwd(), './', webpackDev)
// : path.join(defaultConfigDir, webpackDev),
// babelConfig: userHasWorkspaceBabel
// ? path.join(process.cwd(), './', babelConfig)
// : path.join(defaultConfigDir, babelConfig),
// postcssConfig: userHasWorkspacePostCSS
// ? path.join(process.cwd(), './', postcssConfig)
// : path.join(defaultConfigDir, postcssConfig)
// };
const userWorkspace = path.join(config.workspace);
const pagesDir = path.join(userWorkspace, 'pages/');
const userTemplatesDir = path.join(userWorkspace, 'templates/');
Expand Down
16 changes: 0 additions & 16 deletions packages/cli/src/templates/404.html

This file was deleted.

13 changes: 0 additions & 13 deletions packages/cli/src/templates/app-template.js

This file was deleted.

Loading