Permalink
Browse files

API overhaul, internal refactor

  • Loading branch information...
tannerlinsley committed Oct 9, 2018
1 parent 320be36 commit ce3d2819af78c812abd4512cdef17ebd926d211d
Showing with 1,149 additions and 923 deletions.
  1. +2 βˆ’0 .gitignore
  2. +1 βˆ’1 .travis.yml
  3. +1 βˆ’1 docs/concepts.md
  4. +50 βˆ’41 docs/plugins.md
  5. +2 βˆ’1 package.json
  6. +27 βˆ’0 packages/react-static-example-basic/hooks.browser.js
  7. +27 βˆ’0 packages/react-static-example-basic/hooks.node.js
  8. +11 βˆ’6 packages/react-static-example-cordova/static.config.js
  9. +16 βˆ’7 packages/react-static-example-less-antdesign/static.config.js
  10. +1 βˆ’0 packages/react-static-example-tailwindcss/static.config.js
  11. +1 βˆ’0 packages/react-static-example-typescript/static.config.js
  12. +3 βˆ’0 packages/react-static-plugin-emotion/.babelrc
  13. +2 βˆ’0 packages/react-static-plugin-emotion/.gitignore
  14. +0 βˆ’11 packages/react-static-plugin-emotion/index.js
  15. +11 βˆ’1 packages/react-static-plugin-emotion/package.json
  16. +8 βˆ’0 packages/react-static-plugin-emotion/src/node.api.js
  17. +2 βˆ’0 packages/react-static-plugin-preact/.gitignore
  18. +4 βˆ’3 packages/react-static-plugin-preact/package.json
  19. +2 βˆ’2 packages/react-static-plugin-preact/{index.js β†’ src/node.api.js}
  20. +2 βˆ’0 packages/react-static-plugin-sass/.gitignore
  21. +0 βˆ’42 packages/react-static-plugin-sass/index.js
  22. +4 βˆ’3 packages/react-static-plugin-sass/package.json
  23. +42 βˆ’0 packages/react-static-plugin-sass/src/node.api.js
  24. +2 βˆ’0 packages/react-static-plugin-styled-components/.gitignore
  25. +4 βˆ’3 packages/react-static-plugin-styled-components/package.json
  26. +6 βˆ’6 packages/react-static-plugin-styled-components/{index.js β†’ src/node.api.js}
  27. +1 βˆ’1 packages/react-static/src/browser/components/Link.js
  28. +1 βˆ’1 packages/react-static/src/browser/components/Prefetch.js
  29. +1 βˆ’1 packages/react-static/src/browser/components/PrefetchWhenSeen.js
  30. +1 βˆ’1 packages/react-static/src/browser/components/RouteData.js
  31. +1 βˆ’1 packages/react-static/src/browser/components/Router.js
  32. +1 βˆ’1 packages/react-static/src/browser/components/RouterScroller.js
  33. +1 βˆ’1 packages/react-static/src/browser/index.js
  34. +8 βˆ’5 packages/react-static/src/commands/bundle.js
  35. +2 βˆ’3 packages/react-static/src/commands/export.js
  36. +20 βˆ’15 packages/react-static/src/commands/start.js
  37. +2 βˆ’2 packages/react-static/src/index.js
  38. +2 βˆ’2 packages/react-static/src/static/RootComponents.js
  39. +3 βˆ’3 packages/react-static/src/static/__tests__/buildXML.test.js
  40. +87 βˆ’0 packages/react-static/src/static/buildHTML.js
  41. +1 βˆ’1 packages/react-static/src/static/buildXML.js
  42. +1 βˆ’1 packages/react-static/src/static/components/BodyWithMeta.js
  43. +91 βˆ’91 packages/react-static/src/static/components/HeadWithMeta.js
  44. +34 βˆ’26 packages/react-static/src/static/exportRoute.js
  45. +17 βˆ’0 packages/react-static/src/static/exportRoutes.js
  46. +27 βˆ’0 packages/react-static/src/static/exportSharedRouteData.js
  47. +1 βˆ’2 packages/react-static/src/static/exporter.js
  48. +1 βˆ’1 packages/react-static/src/static/{threadedExporter.js β†’ exporter.threaded.js}
  49. +38 βˆ’0 packages/react-static/src/static/extractTemplates.js
  50. +96 βˆ’0 packages/react-static/src/static/fetchRoutes.js
  51. +11 βˆ’0 packages/react-static/src/static/fetchSiteData.js
  52. +5 βˆ’5 packages/react-static/src/static/generateBrowserPlugins.js
  53. +82 βˆ’72 packages/react-static/src/static/getConfig.js
  54. +0 βˆ’223 packages/react-static/src/static/getRoutes.js
  55. +68 βˆ’0 packages/react-static/src/static/getRoutes/getRoutesFromPages.js
  56. +34 βˆ’0 packages/react-static/src/static/getRoutes/index.js
  57. +81 βˆ’0 packages/react-static/src/static/getRoutes/normalizeAllRoutes.js
  58. +38 βˆ’0 packages/react-static/src/static/getRoutes/normalizeRoute.js
  59. +15 βˆ’292 packages/react-static/src/static/index.js
  60. +26 βˆ’0 packages/react-static/src/static/preparePlugins.js
  61. +48 βˆ’0 packages/react-static/src/static/prepareRoutes.js
  62. +21 βˆ’29 packages/react-static/src/static/webpack/index.js
  63. +2 βˆ’0 packages/react-static/src/static/webpack/webpack.config.prod.js
  64. +3 βˆ’0 packages/react-static/src/utils/binHelper.js
  65. +40 βˆ’1 packages/react-static/src/utils/{shared.js β†’ browser.js}
  66. +6 βˆ’14 packages/react-static/src/utils/index.js
@@ -24,3 +24,5 @@ package-lock.json
tmp
yarn-debug.log*
yarn-error.log*
packages/*/node.api.js
packages/*/browser.api.js
@@ -3,4 +3,4 @@ language: node_js
node_js:
- stable
script:
- npm test
- yarn ci
@@ -287,7 +287,7 @@ To learn more about how `react-router` components work, visit [React-Router's Do

# Webpack Customization and Plugins

React-Static ships with a wonderful default webpack config, carefully tailored for react development. It should support a majority of use-cases on its own. But, in the case you do need to modify the webpack configuration, use the handy [`webpack` property in your `static.config.js` file](/docs/config.md/#webpack).
React-Static ships with a wonderful default webpack config, carefully tailored for react development. It should support a majority of use-cases on its own. But, in the case you do need to modify the webpack configuration, you can create a `node.api.js` file in your project and use the handy [webpack API](/docs/config.md/#webpack) to extend it!

# Using Preact in Production

@@ -1,93 +1,103 @@
# Plugins

React Static ships with a simple plugin system that allows both plugin creators and site developers extend React-Static's built-in functionality.
React Static ships with a simple plugin API that allows both plugin creators and site developers extend React-Static's core functionality.

## Official Plugins

See the [/docs#plugins](Readme's Plugin section) for the official list of supported react-static plugins

## Installing A Plugin

There are 2 ways to install plugins:

- **NPM**. You can install any react-static compatible plugin via `npm`. Once it is installed, it can be used by React Static.
- **Locally via the `/plugins` directory** - If you have a custom plugin or are developing a plugin locally, you can place your plugin directory in the `/plugins` directory in your project roo. It can then be used by React Static.

## Using Plugins

You can use plugins 3 different ways:
Once a plugin is installed, you can add use and configure it by adding it to the `plugins` array in your `static.config.js`:

- `static.config.js` - Little did you know your `static.config.js` file is already a fancy built-in plugin! Any [plugin hooks](#plugin-api) documented here can also be used directly in your `static.config.js`.
- The `/plugins/` directory in the root of your project. Any file you place here can be added to the `plugins: []` array in your `static.config.js`.
- By installing it as a `node_module`. You can install any react-static compatible plugin via `npm` and add it to the `plugins: []` array in your `static.config.js`.
```javascript
// static.config.js
#### Plugin Resolution
export default {
plugins: [
'react-static-plugin-emotion',
'my-custom-plugin'
]
}
```

#### Plugin Execution and Order

**ORDER IS IMPORTANT!!!** Plugins are executed in the order that they are defined in the `plugins: []` array in the `static.config.js`. Also, any methods used directory in the `static.config.js` will be performed last.

#### Plugin Resolution
Plugins are resolved in this order:

1. Plugins with an absolute path. Eg. `~/path/to/my/plugin.js` would resolve to that path.
2. Plugins found in the `/plugins` directory of your project root. Eg. `myPlugin` would resolve to `/plugins/myPlugins.js`.
3. Plugins found in `node_modules`. Eg. `react-static-plugin-emotion` would resolve to `node_modules/react-static-plugin-emotion`.

#### Plugin Options
## Plugin Options

Plugins can be passed options by using an array (similar to how babel and eslint work).
- The first item in the array is the `plugin name string`
- The second item in the array is the `options object` that will be passed to the plugin


```javascript
export default {
plugins: [
[
'react-static-plugin-awesome',
'react-static-plugin-awesomeness',
{
awesomeOption: true,
isAwesome: true,
}
]
]
}
```

## Official Plugins

See the [/docs#plugins](Readme's Plugin section) for the official list of supported react-static plugins

## Building A Plugin
## Plugin API

A plugin is currently comprised of either
- A single `plugin-name.js` file, which is provided the **node/server** plugin API
- A plugin directory containing
- An `index.js` file, which is provided the **node/server** plugin API
- A `browser.js` file, which is provided the **browser** plugin API
Plugins at the end of the day, are just a `directory` with the following files at the directory's root:
- `node.api.js` - Exposes the [Node Plugin API](#node-plugin-api)
- `browser.api.js` - Exposes the [Browser Plugin API](#browser-plugin-api)

The `index.js` file is used in the server-side/cli/node context and implements all of the [Node Plugin API hooks](#node-plugin-api) found below
The `browser.js` file is used in the browser context and implements all of the [Node Plugin API hooks](#browser-plugin-api) found below

## Why separate server and browser entry points for plugins?
We use separate entry points for server and browser context so as to not create conflict with imports that may not be supported in both environments. This is opposite a react-static app, where you are advised to write both browser and node-safe code throughout.
## Why separate node and browser entry points for plugins?
We use separate entry points for node and browser context so as to not create conflict with imports that may not be supported in both environments.

Both plugin file types must export a `function` as the `default export`. That function recieves **plugin options from the user (optional)** and then **returns an `object`** providing any **hook methods** you need to implement
To use either API, the corresponding file must:
- Provide a `function` as the `default export`
- That function recieves **plugin options from the user (optional)**
- **Return an `object`** providing any **API methods** to implement

Here is an example of what a plugin typically looks like:
Here is an **pseudo** example of what a plugin typically looks like:

```javascript
export default pluginOptions => ({
someHook: (hookItem, hookOptions) => {
reducerMethod: (Item, Options) => {
// Do something amazing!
return hookItem
return Item
},
anotherHook: (hookItem, hookOptions) => {
mappedMethod: (Options) => {
// Do something amazing!
return hookItem
return true
}
})
```

## Plugin Execution and Order

**ORDER IS IMPORTANT!!!** Plugins are executed in the order that they are defined in the `plugins: []` array in the `static.config.js`. Also, any hooks used directory in the `static.config.js` will be performed last.

## Plugins must be compiled if installed via node_modules
#### Plugins must be compiled if installed via node_modules

If a plugin is installed via any method other than the `plugins` directory, it will not be transformed by react-static's `.babelrc` runtime, so you **must compile your plugin to be ES5 compatible if you distribute it**. This can be done via `@babel/core` and the babel-cli. The [react-static-plugin-styled-components](https://github.com/nozzle/react-static-plugin-styled-components) plugin does this and is a prime example to follow.

## Node Plugin API

Plugins hooks are executed throughout the lifecycle of a react-static build in the order below:
Plugins methods are executed throughout the lifecycle of a react-static build in the order below:

#### `config: Function`

A hook to modify the final `static.config.js` for React Static.
A method to modify the final `static.config.js` for React Static.

- Arguments:
- `config{}` - The `static.config.js`
@@ -109,6 +119,7 @@ Append arbitrary JSX to the Head component of the application.
Head: ({ meta }) => (
<React.Fragment>
<link rel="stylesheet" href="..." />
<link rel="stylesheet" href="..." />
</React.Fragment>
)
```
@@ -159,6 +170,4 @@ An array of plugins that this plugin depends on. Follows the same format as `sta

## Browser Plugin API

#### `plugins: Array(plugin)`

An array of plugins that this plugin depends on. Follows the same format as `static.config.js` does for importing plugins and options.
There are no browser methods yet! Let's add some :)
@@ -8,7 +8,8 @@
"buildDocs": "cd www && yarn && yarn build",
"serveDocs": "serve www/dist -p 3000",
"test": "yarn prettier && lerna run test",
"prettier": "prettier --config .prettierrc.js {scripts,www/src/,packages/*/{src,node}}/**/*.js --write"
"prettier": "prettier --config .prettierrc.js {scripts,www/src/,packages/*/{src,node}}/**/*.js --write",
"ci": "yarn build && yarn test"
},
"husky": {
"hooks": {
@@ -0,0 +1,27 @@
import axios from 'axios'

export default {
getSiteData: () => ({
title: 'React Static',
}),
getRoutes: async () => {
const { data: posts } = await axios.get(
'https://jsonplaceholder.typicode.com/posts'
)
return [
{
path: '/blog',
getData: () => ({
posts,
}),
children: posts.map(post => ({
path: `/post/${post.id}`,
component: 'src/containers/Post',
getData: () => ({
post,
}),
})),
},
]
},
}
@@ -0,0 +1,27 @@
import axios from 'axios'

export default {
getSiteData: () => ({
title: 'React Static',
}),
getRoutes: async () => {
const { data: posts } = await axios.get(
'https://jsonplaceholder.typicode.com/posts'
)
return [
{
path: '/blog',
getData: () => ({
posts,
}),
children: posts.map(post => ({
path: `/post/${post.id}`,
component: 'src/containers/Post',
getData: () => ({
post,
}),
})),
},
]
},
}
@@ -17,10 +17,8 @@ export default {
return html
},
Document: class CustomHtml extends Component {
render () {
const {
Html, Head, Body, children, renderMeta,
} = this.props
render() {
const { Html, Head, Body, children, renderMeta } = this.props

return (
<Html>
@@ -53,6 +51,7 @@ export default {
// Serve from the ios build folder
contentBase: path.resolve(__dirname, './platforms/ios/www/'),
},
// TODO: This is deprecated, use config.hooks.webpack
webpack: (config, { stage }) => {
if (stage !== 'dev') {
// Cordova serves from file, so relative links, please.
@@ -63,14 +62,20 @@ export default {
onStart: async () => {
// Replace content src with webpack dev server
const cordovaConfig = await fs.readFile(filePath, 'utf8')
const replacement = cordovaConfig.replace('src="index.html"', 'src="http://localhost:3000"')
const replacement = cordovaConfig.replace(
'src="index.html"',
'src="http://localhost:3000"'
)
await fs.writeFile(filePath, replacement, 'utf8')
execSync('cordova run', { stdio: [null, null, 2] })
},
onBuild: async () => {
// Replace content src with index.html
const cordovaConfig = await fs.readFile(filePath, 'utf8')
const replacement = cordovaConfig.replace('src="http://localhost:3000"', 'src="index.html"')
const replacement = cordovaConfig.replace(
'src="http://localhost:3000"',
'src="index.html"'
)
await fs.writeFile(filePath, replacement, 'utf8')
},
}
@@ -30,7 +30,9 @@ export default {
title: 'React Static',
}),
getRoutes: async () => {
const { data: posts } = await axios.get('https://jsonplaceholder.typicode.com/posts')
const { data: posts } = await axios.get(
'https://jsonplaceholder.typicode.com/posts'
)
return [
{
path: '/blog',
@@ -54,23 +56,25 @@ export default {
return html
},
Document: class CustomHtml extends Component {
render () {
const {
Html, Head, Body, children, renderMeta,
} = this.props
render() {
const { Html, Head, Body, children, renderMeta } = this.props

return (
<Html>
<Head>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="viewport"
content="width=device-width, initial-scale=1"
/>
{renderMeta.styleTags}
</Head>
<Body>{children}</Body>
</Html>
)
}
},
// TODO: This is deprecated, use config.hooks.webpack
webpack: (config, { stage, defaultLoaders }) => {
/*
* TypeScript Support
@@ -178,7 +182,12 @@ export default {

config.module.rules = [
{
oneOf: [jsTsLoader, lessLoader, defaultLoaders.cssLoader, defaultLoaders.fileLoader],
oneOf: [
jsTsLoader,
lessLoader,
defaultLoaders.cssLoader,
defaultLoaders.fileLoader,
],
},
]

@@ -6,6 +6,7 @@ import postcssFlexbugsFixes from 'postcss-flexbugs-fixes'
import tailwindcss from 'tailwindcss'

export default {
// TODO: This is deprecated, use config.hooks.webpack
webpack: (config, { stage, defaultLoaders }) => {
let loaders = [
{
@@ -31,6 +31,7 @@ export default {
},
]
},
// TODO: This is deprecated, use config.hooks.webpack
webpack: config => {
// Add TypeScript Path Mappings (from tsconfig via webpack.config.js)
// to react-statics alias resolution
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env"]
}
@@ -1,2 +1,4 @@
.history
node_modules
/node.api.js
/browser.api.js

This file was deleted.

Oops, something went wrong.
Oops, something went wrong.

0 comments on commit ce3d281

Please sign in to comment.