Bot releases are hidden (Show)
Published by leebenson about 7 years ago
/graphql
when using external GraphQL endpointconfig.enableGraphQLServer|setGraphQLEndpoint()
/graphql
)config.enableGraphQLServer()
should be called isomorphically!config.setGraphQLSchema()
for passing the schema to the GraphQL server (use inside a SERVER
block only!)Published by leebenson about 7 years ago
Published by leebenson about 7 years ago
Published by leebenson about 7 years ago
Kit v2 introduces a few significant improvements that make it easier to upgrade between kits, and power-up your ReactQL experience:
React has been bumped to the new v16, and renderToString
has been replaced with renderToStream
-- for turbo-powered first page rendering of React to HTML.
Early tests have shown a promising reduction from 12ms+ for React-only rendering (no GraphQL) to 4-5ms on my local Macbook Pro, using out-the-box defaults.
What's more, on Node 8+, the asynchronous createReactHandler
that sets up the Redux store, runs Helmet, initialises the component tree and starts the stream, has been benchmarked as low as 0.48ms on my same machine!
Your ReactQL project will be faster than ever.
In kit v1.x, the lines between ReactQL and your client code were a little blurry. Editing the Apollo endpoint meant modifying config/project.js
, which was a file that Webpack also used to assess whether to show the bundle optimiser post-build.
If you wanted to add anything more to the server or browser, you'd typically need to delve into kit/*
files and make changes.
Now, the separation between two is clearer than ever. ReactQL v2.x introduces a new Config
singleton instance that provides 'hooks' into adding functionality to the standard config, without mashing together custom code.
ReactQL is and always has been a 'starter kit', and will continue to be so. But now the framework-esque separation of client and kit code paves the way to clean abstractions, and easier upgrading.
In a future ReactQL CLI version, it's possible that you'll be able to upgrade an active project to the latest kit with a single command, instead of the current process of creating a new project, copying over src
and manually/surgically editing kit files.
ReactQL was originally focused on being a front-end starter kit. But the effort put into creating a fast and capable SSR stack means you now also have an ideal home to run a monolithic GraphQL server, too.
Starting with 2.0, you're now able to add a GraphQL server easily, by add a few lines of code to src/app.js
:
src/app.js
// Import the new `Config` singleton instance
import config from `kit/config`;
// Enable GraphQL on the server -- this code will be eliminated from the browser bundle
if (SERVER) {
config.enableGraphQLServer(require('src/path/to/schema').default);
}
That's it!
The above mounts a GraphQL server inside Koa at /graphql
, gives you a visual UI to query data via GraphiQL, and sets up Apollo to point to the server URI automatically. It takes care of your server-side CORS config, and adds POST body processing for incoming GraphQL queries.
It also adds apollo-local-query to Apollo client initialisation on the server, so instead of routing requests over the network, GraphQL queries are made against the schema already loaded in memory -- eliminating TCP/IP overhead.
Of course, if you want to connect to a third-party endpoint, you can still do that easily:
config.setApolloURI('http://example.com/graphql');
(Special thanks to graph.cool for allowing us to use their service in the starter kit in 1.x. Hopefully the move above will also take some load off your server 😄)
With the new Config
API, you no longer need to edit kit/lib/redux.js
to add custom reducers.
Instead, you can add them to src/app.js
and keep reducers in userland:
import config from `kit/config`;
// Create a reducer somewhere, shaped as { state, reducer() } -- this will
// probably be imported from a separate file
const someReducer = {
// This is the reducer's initial state
state: {
someSetting: true,
},
reducer(state, action) {
// ... reducer code to do something with `state`
}
}
// Add the reducer, and specify the reducer key
settings.addReducer('someKey', someReducer);
You can now add custom GET|POST|PUT|PATCH routes to the server, like so:
// We can add custom routes to the web server easily, by using
// `config.add<Get|Post|Put|Patch>Route()`. Note: These are server routes only.
config.addGetRoute('/test', async ctx => {
ctx.body = 'Hello from your ReactQL route.';
});
Routes will be added in insertion order, to obey your precedence rules.
koa-bodyparser
is enabled by default, to process POST requests for a built-in GraphQL server or custom POST routes.
By default, it'll process JSON and form requests automatically.
You can disable with:
config.disableBodyParser();
Or pass in your own custom options to koa-bodyparser
with:
config.setBodyParserOptions({
// Example of a config option -- see https://github.com/koajs/bodyparser
jsonLimit: '8mb',
})
The custom 404 handler added in 2.0 is one of several planned API 'hooks' that allow you to attach custom functionality to common server and browser entry points, without editing kit code.
This example ships in the starter kit:
config.set404Handler((ctx, store) => {
// For demo purposes, let's get a JSON dump of the current Redux state
// to see that we can expect its contents
const stateDump = JSON.stringify(store.getState());
// Explicitly set the return status to 404. This is done for us by
// default if we don't have a custom 404 handler, but left to the function
// otherwise (since we might not always want to return a 404)
ctx.status = 404;
// Set the body
ctx.body = `This route does not exist on the server - Redux dump: ${stateDump}`;
});
You get access to the Koa ctx
request context object as well as the Redux store
, giving you the flexibility to handle responses in whichever way makes the most sense for your application.
In future kits, expect hooks to crop up in places like redirect and error handling.
src
layout; more commentaryThe out-the-box sample app that comes with a new ReactQL project is now better organised. Instead of a single src/app.js
file, components have been given their own files/folders, and tons of extra commentary has been added to give you a better idea of what's happening under the hood.
Whilst src/app.js
is still required in every project (that's where ReactQL will look for your app code), now the file should serve two simple purposes:
<Html> -> <div id="main"/>
This best practice will make it easier to organise your code, and know what goes where.
Several components also demonstrate the pattern of asset co-location; images and SASS code is often in the same directory as the calling .js
file, to make it clear which assets belong to which React components.
v2.0 documentation will land on https://reactql.org/docs soon.
All changes:
config/project.js
Config
class to kit/config.js
, initialised as a singleton to use globally in src/app.js
addReducer(key, reducer)
-- adds a new Redux reducer in the shape of {state, reducer()}
disableBodyParser()
-- disables koa-bodyparser
in the server configsetBodyParserOptions(opt)
-- pass custom koa-bodyparser
options to override defaultsaddRoute(method, route, handler)
-- add new Koa routeaddGetRoute(route, handler)
-- add new GET routeaddPostRoute(route, handler)
-- add new POST routeaddPutRoute(route, handler)
-- add new PUT routeaddPatchRoute(route, handler)
-- add new PATCH routeaddDeleteRoute(route, handler)
-- add new DELETE routeset404Handler(func)
-- sets a custom 404 handler, which is given (state, store)
inside createReactHandler()
enableGraphQLServer(schema, endpoint = '/graphql', graphiql = true)
-- enables built-in GraphQL web server at /graphql
, (optionally) enables up GraphiQLsetGraphQLEndpoint(uri)
-- sets the GraphQL server URI for Apollo. For use with external GraphQL servers.render
with the new hydrate
method, for rehydrating server HTML.data-reactid
tags no longer appear in resulting HTML, saving bandwidthapollo-local-query
, for bypassing the network when using a local GraphQL servercreateNeworkInterface()
, for memoizing network interface creation on the serverrenderToStream
instead of renderToStaticMarkup
<Html>
component to take component tree as a child prop, and not as a rendered stringkcors
to allow cross-origin requests by default (for REST/GraphQL)serverClient()
method in kit/lib/apollo.js
, to avoid unnecessary apollo-local-query
bundling on the browsergetURL()
in kit/lib/env.js
, to allow a boolean flag to enable HTTPSgetServerURL()
to kit/lib/env.js
, to explicitly get the web server host and port (typically for GraphQL)kib/lib/redux.js
to derive config from the config.reducers
Mapnpm run build-analyze
option, to open a browser window showing the bundle analysis report after buildingBUNDLE_ANALYZER
config option -- now uses the above commandsrc
folder<root>/reducers
to src/reducers
, to reflect best practices{state, reducer()}
reducer shape (now exported bare; no longer attached to a reducer key)vendor.<hash>.js
bundle (383kb -> 374kb... 107kb gzipped... 90.9kb Brotli!)npm run build-static
builds an an invalid <script>
include for the Webpack manifest, pending https://github.com/reactql/kit/issues/55
Published by leebenson about 7 years ago
kit/webpack/common.js
Published by leebenson about 7 years ago
--inspect
to server fork in development, to enable debuggingPublished by leebenson about 7 years ago
sourceMap
option to newer options
objectPublished by leebenson about 7 years ago
url()
imports in CSSNano, by disabling normalizeUrl
Published by leebenson about 7 years ago
Published by leebenson over 7 years ago
npm start
compression-webpack-plugin
in favour of zopfli-webpack-plugin
Published by leebenson over 7 years ago
webpack.optimize.ModuleConcatenationPlugin
-- shaves a few KB of the vendor bundle sizePublished by leebenson over 7 years ago
eslint-plugin-jsx-a11y
^5.1.0, fixing ESLint v3 issuesjest
test runner (currently no tests)npm test
option to package.json
.travis.yml
for building and testing lint status via Travis-CIPublished by leebenson over 7 years ago
Published by leebenson over 7 years ago
Published by leebenson over 7 years ago
Published by leebenson over 7 years ago
OccurrenceOrderPlugin
(on in default in Weback v2)module.loaders
-> module.rules
, and loaders.loaders
-> rules.use
Published by leebenson over 7 years ago
postcss-loader
per the fix at https://github.com/postcss/postcss-loader/issues/250
Published by leebenson over 7 years ago
kit/lib/redux.js
to provide a pattern for adding custom reducers outside of Apolloreducers/counter.js
sample reducer, for incrementing a counter<ReduxCounter>
example to src/app.js
for triggering an increment action and listening for store changesreact-redux
, for passing Redux store state to React via propsredux-thunk
, for allowing custom actions that return functions, giving them access to dispatch
related actionsseamless-immutable
, for enforcing immutability in custom Redux statePublished by leebenson over 7 years ago
kit/lib/env.js
, where isProduction
was always returning false
Dockerfile
, for building a production web server Docker image.dockerignore
, copied from the existing .gitignore
to avoid unnecessary build contextyarn.lock
-- the official advice is to avoid Yarn at present, due to certain third-party NPM packages relying on 'postinstall' hooks to build binaries from sourcepackage-lock.json
, for faster builds with NPM v5iltorb
and node-zopfli
, binary packages required for Brotli and Zopfli compression respectivelyPublished by leebenson over 7 years ago
graphql-tag
loader, for storing queries in .gql|graphql
files (closes #32)src/app.js
to use file queriessrc/queries/all_messages.gql
, for retrieving GraphCool endpoint messagessrc/queries/message.gql
, imported by all_messages.gql
as a query fragmentgraphql-tag
loader config to kit/webpack/base.js