- Update packages
- Drop styled-jsx support
- Fix cjs files not being loaded by
file-loader
- Fix config not passed to
getPageData
function.
- Breaking change in universal-react's
renderOnServer()
arguments.
// Before
export default async function renderOnServer(ReactComponent, url, props = {}, cspNonce) {} // Declaration
const { content, context } = await render(App, req.originalUrl, { config: getConfig() }, res.locals.cspNonce); // Usage
// After
export default async function renderOnServer(ReactComponent, url, props = {}, { cspNonce, appDecorator, document, config } = {}) {} // Declaration
const { content, context } = await render(App, req.originalUrl, {}, { config: getConfig(), cspNonce: res.locals.cspNonce }); // Usage
- Added possibility to override the HTML document template in universal-react.
- Added
appDecorator
option in universal-react server render method to add a wrapper function around the entire React app before passing it toReactDOMServer.renderToString()
. - Config object is now passed to client also in a case when server-side rendering fails in universal-react.
- Add optional
DISABLE_SSR
environment variable to disable server-side rendering in universal-react.
Reworked server startup logic, fixing issues with hot reload, which would sometimes cause the server to stop updating during development.
- No breaking API changes
- We no longer rely on hacky plugins that weren't fully updated to webpack 5 to start the server during development.
build-server.js
is no longer written to disk during developmentbuild-server.js
now exports the express instance, and doesn't start a web server (that is done by thenpm start
script)
- If styled-jsx is enabled, you can now enable SCSS support by running
npm install @styled-jsx/plugin-sass
- Added optional styled-jsx integration. To use it, configure
styledJSX: true
and runnpm install styled-jsx
- Added gzip in universal-react template in production.
- Added
helmet.js
integration to the universal-react boilerplate. We export a wrapper around helmet that passes in some defaults. If you want to add it to an existing project, add the middleware to your server/entry.js:
import helmet from '@optimistdigital/create-frontend/universal-react/helmet';
// After initializing server
server.use(helmet());
// helmet middleware adds a cspToken to res.locals. Pass it to the render function
const { content, context } = await render(App, req.originalUrl, { config: getConfig() }, res.locals.cspNonce);
If you don't want to use content-security-policy, you can disable it and skip passing the nonce:
server.use(helmet(opts => ({ ...opts, contentSecurityPolicy: false })));
- Updated to webpack 5. No new features/API changes, but the webpack upgrade may break some things.
- Dropped support for node < 12.
- Changed from node-sass to dart-sass. This fixes an issue where build didn't work using new Macbooks with the M1 chip.
- You may see an error if your client-side code depends on node.js core modules:
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default. This is no longer the case. Verify if you need this module and configure a polyfill for it. The polyfills can be added in create-frontend.conf.js through the
editConfig
property. If the error is caused by a third party library, make sure you're using the latest version. - If you were using the require function to link images, it now returns an ES Module, so you need to add
.default
to the end:Alternatively, import them at the top of the file with ES6 import syntax.- <img src={require('./path-to-image.png')} /> + <img src={require('./path-to-image.png').default} />
- Simplified the default boilerplate
- Eslint and Prettier configs are now in
package.json
instead of separate files - Eslint plugins are no longer listed in
dependencies
, since they are implicit dependencies of create-frontend.
- Eslint and Prettier configs are now in
- Added the
jsx-a11y
Eslint plugin to help detect accessibility problems.
- Eslint 7 is now required. If you have Eslint 6 in your dependencies, either upgrade it to 7 or remove it entirely (it will be downloaded from create-frontend's dependencies).
- You should remove the following eslint plugins from your dependencies if present:
eslint-plugin-import
,eslint-plugin-jsx-a11y
,eslint-plugin-react
,eslint-plugin-react-hooks
. They are now managed by create-frontend. - After updating, it might be necessary to reinstall dependencies to clear up issues:
rm -rf node_modules && rm package-lock.json && npm install
- In the universal-react template, environment variables from
.env
are now automatically updated when that file is changed. - Added
useAppData
hook so users don't have to use the context directly when reading app data.
Simplified universal-react template's entry files. Previously, we had two different files for the server (entry.js and server.js) which was confusing. entry.js
also contained code that was irrelevant to the application and so it has been moved to create-frontend.
- The old
server/entry.js
has been removed, andserver/server.js
has been renamed toserver/entry.js
. - The port detection, hot reloading and createServer code now lives in create-frontend
If you have an existing project with universal-react:
- Delete
server/entry.js
. If you wrote some custom code here, it should be moved toserver/server.js
- Rename
server/server.js
toserver/entry.js
- All templates now generate
.gitignore
andREADME.md
files. They will not be generated if they already exist in the directory - The default template now includes an
index.html
file - Updated dependencies
- Added error handling to the universal-react template: if no routes are matched, a 404 page will be shown. If there are errors while rendering the React app, server rendering is skipped and on the client, an error boundary is used to display an error page.
- The
render
function in the universal-react template now acceptsnull
as the first argument, to skip server rendering.
- Updated dependencies. We're now using babel 7.8, which gives the nullish coalescing operator.
- Optional chaining is stage 4! Added @babel/plugin-proposal-optional-chaining
- Fixed issue in babel configuration that resulted in multiple copies of core-js being shipped.
- Dependency updates
- The default template no longer uses an ESLint config that relies on the React plugin. This fixes a warning in the console that says you are using the React plugin but don't have React installed. If updating from an existing project, you may change
eslint-config.js
toeslint-config-vanilla.js
in your.eslintrc
file. - The flowtype ESLint plugin has been removed. If you want to continue linting Flow in your project, you can add the plugin manually in your
.eslintrc
file.
- The universal-react template now also generates a
.gitignore
file. - Updates to dependencies
Breaking: getPageData
and render
function signatures changed. The previous solution didn't give enough flexibility to integrate smoothly with data management libraries like Redux/Mobx.
- The
render
functions (on both client and server) now acceptprops
as the third argument instead ofbackendData
. This will be passed as a prop to your top level React component (App.js), and also passed toApp.getPageData
as the 2nd argument. These props don't get automatically added toappDataContext
- if you want to add them, put them in the return value ofgetPageData
explicitly.
- If you were reading
backendData
contents in your React app through theappDataContext
, you now have to pass that explicitly ingetPageData
:
App.getPageData = async (location, props) => {
// Finds the current route component and gets data from that
const routeDataSetter = await getRouteData(location, routes, props);
return prevState => ({
// Merge in the data from the route components
...routeDataSetter(prevState),
// You can set data here that will be added on every page
config: prevState.config || props.config,
});
};
-
Changes to universal-react template, mainly to add better universal data fetching capabilities:
getPageData
will now get called on client-side route changes as well.getPageData
should now return an updater function, instead of a plain object- Added boilerplate to the template to handle fetching data for specific routes. Each route's component can now have a
getPageData
function (more info in docs) - Router no longer needs
url
passed to it in App.js - Changed the arguments passed to
render()
on the server. The second argument is now theurl
(previously request object). The third argument is now a generic data object that will be passed on to the application (previously config)
- If you were using App.getPageData, it should be refactored something like this:
// Old:
App.getPageData = async ({ req }) => ({
foo: 'bar',
});
// New (note that this will now run on every page change):
App.getPageData = async (location, params) => prevState => ({
foo: 'bar',
});
- In the server,
render()
should be called with different arguments:
// Old:
const { content, context } = await render(App, req, getConfig());
// New:
const { content, context } = await render(App, req.originalUrl, { config: getConfig() });
- Router component from universal router now passes the props through to react-router
- Made Babel configurable:
babel.config.js
and.babelrc
files are now respected, and a babel config has been exposed as public API so it can be extended. If existing projects had either of these two files, you should ensure that they extend@optimistdigital/create-frontend/babel-config
, otherwise they might break. - Added eslint plugin for hooks
- Changed React template's App component to use a function component instead of a class.
- Removed
browserslist
from create-frontend config. Instead, it's now in the package.json as a separate field, so it can be detected by automatically by tools. If you're upgrading and had this configured previously, you can move the browserslist value to your package.json as a top level field as documented here
- Added flexbugs-fixes postcss plugin, which fixes some flex bugs, mainly in IE11
- Removed babel-plugin-inline-react-svg - this caused problems with absolute imports, and was possibly too opinionated to begin with. It's trivial to add this plugin per-project if necessary.
- getBabelOpts is now synchronous so it can be integrated with jest
- Removed Emotion.js. This will probably not be used as extensively, and adds unnecessary complexity to the project. To continue using emotion, you will have to add the
@emotion/babel-preset-css-prop
preset, andbabel-plugin-emotion
plugin.
- Added Docker files for Universal-React template
- Cleaned up initialization logs
- Added node-notifier when there are build errors in development
- Updated template to use core-js directly, instead of @babel/polyfill
- Fixed issue in universal-react template, where certain styles files weren't server-rendering properly in dev mode
- Fixed @babel/preset-env warning that asked for a core-js version to be declared. To apply this fix, you need to replace @babel/polyfill with core-js:
npm install core-js@3 @babel/runtime-corejs3 && npm uninstall @babel/polyfill
- Replace
import '@babel/polyfill;
withimport 'core-js/stable';
- Fixed issue where universal-react template was missing .gitignore
- Adds Universal React template.
- Adds opt-in Emotion.js support
- Adds babel-plugin-inline-react-svg by default
- A free webpack port now gets picked automatically, if the default one is taken by another process
- Many minor changes in implementation details - there shouldn't be any breaking changes, but undocumented functionality might change
- Updated dependencies and internal configuration. No external breaking changes.
- Added
browserslist
config option
- Updated babel to 7.0.0
- Removed
copyPath
- this plugin isn't necessary, because files can be placed in the public directory manually. Other use cases should be rare enough that this plugin can be added on a case-by-case basis. - Consolidated
create-frontend.conf.js
and the package.jsoncreate-frontend
property to affect a single, global, config. This makes the configuration process less confusing and allows the entire config to be in one place, written in JS instead of JSON.
- Fixed resolve-url-loader error in Windows (issue #4)
- Fixed error during create-frontend command if no template is specified
--template=react
will add a React-specific boilerplate-y
flag will skip user confirmation
- The
create-frontend.conf.js
configuration file has been updated:- Replaced
mergeConfig
witheditConfig = (config, options) => newConfig
. This can be used as an escape hatch to add/remove rules/plugins, etc, by providing you with full access to the webpack configuration object. ThemergeConfig
property is no longer supported, because it was a more limited version of the same functionality. - Replaced
mergeDevServerConfig
witheditDevServerConfig
for the same reason.
- Replaced
postcss-import
plugin to the postcss config. This gets rid of the deprecation warning about importing css files from scss.entry.scss
template has been updated to show the proper way to import css files from node_modules.
- Autoprefixer browser support has been bumped up slightly.
- Code that you had in
mergeConfig
can be replaced with the following:
module.exports = {
editConfig: config => {
...config,
...modifications
},
editDevServerConfig: config => {
...config,
...modifications,
}
}
- If you're importing any css files from scss, make sure they end with .css, and don't have node_modules at the beginning:
- @import 'node_modules/normalize.css/normalize';
+ @import 'normalize.css/normalize.css';
-
Updated to webpack 4. There are no breaking changes if you didn't use a
create-frontend.conf.js
file to modify the webpack config directly.If you did, then some things changed: notably, there is no longer an extract-text-plugin, instead, we are using mini-css-extract-plugin. Custom plugins also need to be updated to use the new webpack 4 API.
- Added
mergeDevServerConfig
property to the create-frontend.conf.js configuration file. This can be used to customize the webpack dev server.
- Fixed issue where static files were not being served properly in the dev server: #1
- Fixed html plugin not maintaining nested directory structure when building for production
- Copy plugin now has to be opted into manually (
copyPath
in options). This fixes an error that occured when the user didn't have aclient/copy
directory. This error is now acceptable because the user opted in manually and has to be notified about broken configuration. appendRules
has been renamed toprependRules
. "Append" was misleading, because the webpack rules are actually added to the beginning of theoneOf
array, and will take precendence over the default rules.
- If you used create-frontend.conf.js file with
appendRules
, change it toprependRules
(logic is same) - If you used the default copy path, add
"copyPath": "client/copy"
to your create-frontend configuration in package.json - If you relied on nested .html files being flattened into the public directory, they must now be flat in the source as well
- Files from
client/copy
are now automatically copied into the public directory. Path is customizable in settings
- Added more data to the
opts
object that is passed to the mergeConfig/appendRules/appendPlugins callbacks. It now additionally containspaths
andconfig
objects
- Added globals into eslint config, which are injected into the app by webpack :
__DEVELOPMENT__
,__PRODUCTION__
,__DEBUG__
- Fixed React transforms that were throwing errors during development due to missing dependencies
- html-loader for html-webpack-plugin. This resolves the issue where
<img src="../images/filename.ext">
wasn't properly copying the assets over. PS! Absolute URL's here still don't work.
- html-webpack-plugin is now built-in. Customizable through options (more info in readme)
- Added .vue and .jsx to resolve.extensions by default. They can now be imported in js without adding the extension
- Refactored
create-frontend.conf.js
API. getPlugins and getRules have been replaced with the following (more info in readme):mergeConfig
- allows user to override any configurationappendRules
andappendPlugins
- same as old getPlugins/getRules. Allows user to add new functionality without replacing the entire rules/plugins array