Server, build and client side bootstrapping for next's user-facing applications.
PLEASE DON'T USE THIS OUTSIDE OF USER-FACING FT.COM APPLICATIONS. If you need a good express server with handlebars, metrics etc available consider using n-internal-tool, n-express or copying what you need from n-ui
n-ui has three parts - a server, a client side 'app shell' (js, css & handlebars layout), and a build. Expect things to break if you don't use all 3.
n-ui is a wrapper around n-express which adds templating and asset loading features
npm install @financial-times/n-ui
const app = require('@financial-times/n-ui')(opts)
Where opts is an object supporting all n-express
's options, but with many set to true
by default (see /server/index.js
for details). Additioanl options include
partialsDirectory
String or array - path[s] to load partials from, this in addition to the standardviews/partials
that is set for every applayoutsDir
String - a path to load handlebars views from defults tonode_modules/@financial-times/n-ui/layout
withJsonLd
Boolean - output jsonLD schema information in the page head
n-ui comes bundled with its own build tool - basically webpack
, haikro build
and a little bit of other stuff. To use it, add the following to your Makefile:
build:
nui build
build-production:
nui build --production
watch:
nui watch
To define entry points for your assets use a n-ui-build.config.js
file in the root of your project, which can export any object compatible with n-webpack
This should live in a /client/n-ui-config.js
file
module.exports = {
preset: 'complete', // 'discrete' will turn off ads & various popups
features: {
lazyLoadImages: true // turns individual features on/off. Check `/browser/bootstrap/js/component-initializer.js` for an upto date feature list
}
}
n-ui takes care of loading polyfills etc, and your application code shoudl be wrapped in the bootstrap method
e.g.
import { bootstrap } from 'n-ui';
bootstrap(({ flags , appInfo, allStylesLoaded }) => {
if (flags.get('feature')) {
component.init();
}
allStylesLoaded
.then(() => {
lazyComponent.init();
});
});
Nothing fancy going on here any more 😄. No mixins (though the n-ui-foundations module has a few you will want to use), no tricky critical path css stuff.
@import "n-ui/main"
This will, when using the n-ui build tool, split n-ui's styles into head-n-ui-core.css and n-ui-core.css files, and the server will inline/linnk to these appropriately.
You should be able to work in n-ui as if it's an app - make watch
and make run
should work and serve a demo app on local.ft.com:5005
export NEXT_APP_SHELL=local
then use all your usual make tasks. Your app will build and serve n-ui from your locally installed bower components. You can do this whether you're bower/npm linking n-ui or not
When you release an n-ui tag 3 things happen
- assets are built and deployed to s3, from where they are linked to/downloaded by apps
- the npm package is published
- during work hours (9am to 4pm), all user-facing apps are rebuilt to pick up the changes
Adds link headers to optimise requests for assets, defaulting to preload behaviour
url
- absolute or relative path to the resourcemeta
- object defining additional properties to add to the headerrel
[default: 'preload'] - value of therel
propertyas
- value of theas
property e.g. 'stylesheet'
options
- additional options when creating the headerpriority
- a value of highest will add the link header before all previously added resources that do not specify this (shodul not normally used by apps - used internally to ensure n-ui's resources are always loaded as wuickly as possible)hashed
- if true the path to the asset will be resolved to the equivalent hashed aset path
Anything below here isn't necessarily 100% up to date - n-ui has changed a lot recently and updating the docs is ongoing
Overview of how the n-ui js bundle is delivered
make build run
will- start a server on
localhost:5005
which serves a demo page of most of the core n-ui components. Note: Any changes to templates require restarting the server - build an n-ui bundle that will bootstrap the js and css for the page
- start a server on
make test-unit-dev
will run unit tests in Chrome using karma. To add tests for a new subcomponents, or to only run tests for a single subcomponent, modify thecomponentsToTest
list in karma.config.js. In CI these tests are run in more browsers using saucelabs
To work with n-ui when it's bower linked into an app you will need to export NEXT_APP_SHELL=local
in your app and then proceed exactly as you would for any other component
We hope to be able to a11y test all components before they are used in an app and end up causing lots of applications to fail builds. For now we are testing components in CI using pa11y and this requires some additional set up when creating a new component. Any directory in the root is considered to be a component and will require this additional set up.
- Inside a component directory there must be a
pa11y-config.js
that must return JSON - The must have an
entry
property and and may contain adata
property if required- The
entry
value should point to the main template for the component without any file extension and relative to the component root. - The
data
can be used if you need to pass any fixture data to the component for testing.
- The
Don't - n-ui is no longer a place to dump all next components. If you need to create a new shared component create a new repo for it and use the n-ui-foundations
component to access primitive styles as used in next.
If, for example, you want to use a beta of an origami component in a single app, or use React instead of preact
In your app’s webpack.config.js, you can pass an nUiExcludes
array as an option to nWebpack e.g. nUiExcludes: [‘React’, ‘React-Dom’]
If you pass withNavigation:true
in the init options, you will have navigation data available in res.locals.navigation
. this data comes from polling the navigation API. This data is used to populate the various menus and navigation items on the apps. The following data is available
res.locals.navigation = {
lists: {
navbar_desktop: // data for the main nav in the header (only on large screens)
navbar_mobile: //data for the white strip that appears on the homepage and fastFT pages only on small screens
drawer: //data for the slide-out menu
footer: // data for the footer
}
}
If you also pass withNavigationHierarchy: true
in the init options you get some additonal properties detailing the current page's position in the hierarchy. This is only currently useful on stream pages. The following properties are added:
res.locals.navigation.currentItem // the current item
res.locals.navigation.children //an array of the direct decendents of the current page
res.locals.navigation.ancestors // an array of the parent items of the current page (top level first)
The navigation model also controls the edition switching logic. The following properties are added
res.locals.editions.current // the currently selected edition
res.locals.editions.others // and array of other possible editions
- Our Handlebars engine loads partials from
bower_components
and has a number of additional helpers. It also points to n-layout to provide a vanilla and 'wrapper' layout - Exposes everything in the app's
./public
folder via./{{name-of-app}}
(only in non-production environments, please use next-assets or hashed-assets in production)