Documentation about the project's dependencies
- Dependencies
- Dev dependencies
Overview of the project deps, why we use them, and (not always) quick explanations about them
All the packages listed here are under open source, non-restrictive license (MIT, ISC, etc.)
The order follows the order in package.json (kinda alphabetical but not quite exactly ¯\_(ツ)_/¯)
A JavaScript SDK for tracking events and revenue to Amplitude.
When your want to perform Analytics in any app, people usually go for Google Analytics. We don't. GA is too limited, and huge, with tons of useless stuff. We've used it, and we really don't recommend it for any SPA, especially when playing with universal app because it just sucks.
It's very hard to configure GA with universal apps, you'll end up with wrong analytics insights due to event multi triggers (SSR + CSR). It was built for another world. Not for SPA!
Instead, we use (and recommend) Amplitude instead. The world of analytics is huge, and isn't cheap.
amplitude-js: Top-level amplitude official lib, used by react-amplitude.@amplitude/react-amplitude: React-friendly amplitude lib, non-officially maintained. Really useful when working with react.
Amplitude allows to track events and users behaviour, who are two very different things, even if events are related to users.
Amplitude offers a free plan that allows 10 million events per months ($identity events aren't counted towards events, they're free).
Then, the cheapest plan is Growth, that starts around $48k/year (yup, it's a huge gap)
If you want to benefit from the Growth plan for free, know that it's possible (but limited to 1 years), through their startup Scholarship. They offer Scholarship for non-profit organisation too.
But, a word of caution here, even if you benefit from the scholarship, make sure your business doesn't rely on Growth features when your Scholarship ends.
They told us then always find a way to provide Amplitude at an acceptable price for non-profit
Anyway, Amplitude is one of the best out there for Analytics, if the free plan is enough for your needs, or if you can afford paid plans. Also, their react integration is really good, even though it's not officially maintained and could use some love.
Emotion is a library designed for writing css styles with JavaScript. https://emotion.sh/docs/introduction
Next.js provides CSS-in-js using styled-jsx, but we dislike it for several reasons.
It's not very intuitive to write styles that way and it needs extra dependencies/configuration to work with nested components and such.
Instead, we use Emotion in this project,
which allows to write components using either the styled notation, or the css notation.
@emotion/core: Necessary to use emotion, with built-incssnotation support.@emotion/styled: Necessary to used thestylednotation.emotion-theming: Theming library inspired by styled-components
It's strongly recommended to read the official documentation about how to use it.
When using Emotion, the file must start with /** @jsx jsx */ on top of it.
TL;DR It basically tells the babel compiler to do something different and won't work if not specified.
Sentry provides open-source and hosted error monitoring that helps all software teams discover, triage, and prioritize errors in real-time.
We use Sentry to catch errors that happen within the application. They are available at https://sentry.io/ for any developers in the team.
Those errors are also sent to our Slack channel sentry-monitoring.
@sentry/browser: Package to use from the browser.@sentry/node: Package to use from the server.
Sentry provides 2 different packages, with different abilities (but a very similar API) for browser and server usage.
In the source code, we always use @sentry/node, which is automatically converted at build step by babel. (see next.config.js)
This way, we always use the same import, which is linked to the right package based on the runtime engine target.
We use some of our own packages. They are all hosted on ou GitHub repository, and all under MIT license.
@unly/utils: This is a utility library which contains various helpers. This repository was created because those helpers are used amongst several projects and were copy/pasted, which is a bad practice.@unly/utils-simple-logger: Logger based on Winston with sane default so that it only logserrorin production and filter other logs, while keeping them all in non-production environments. Basically avoids to increase cost by logging useless logs in production.@unly/universal-language-detector: Language detector that works universally (browser + server) - Meant to be used with a universal framework, such as Next.js
React Apollo allows you to fetch data from your GraphQL server and use it in building complex and reactive UIs using the React framework. React Apollo may be used in any context that React may be used.
apollo-boost: Apollo Boost is a zero-config way to start using Apollo Client. It includes some sensible defaults, such as our recommended InMemoryCache and HttpLink, which come configured for you with our recommended settings. Even though it may seems unused, this package is required as peer-dependency.apollo-cache-inmemory: apollo-cache-inmemory is the recommended cache implementation for Apollo Client 2.0. InMemoryCache is a normalized data store that supports all of Apollo Client 1.0's features without the dependency on Redux.apollo-client: Apollo Client is a fully-featured caching GraphQL client with integrations for React, Angular, and more. It allows you to easily build UI components that fetch data via GraphQL.apollo-link-http: The http link is a terminating link that fetches GraphQL results from a GraphQL endpoint over an http connection.apollo-link-context: Easily set a context on your operation, which is used by other links further down the chain.react-apollo: React Apollo allows you to fetch data from your GraphQL server and use it in building complex and reactive UIs using the React framework. React Apollo may be used in any context that React may be used. In the browser, in React Native, or in Node.js when you want to do server-side rendering.
It works fine with both SSR and client-side navigation.
classnamesis just the must-have tool to use to manipulate dynamic className property
classnames: A simple JavaScript utility for conditionally joining classNames together.
It's hard (or at least, non-trivial) to make cookies work universally with Next.js
js-cookie: Used to WRITE cookies from the client side. A simple, lightweight JavaScript API for handling browser cookiescookies: Used to WRITE cookies from the server side. Cookies is a node.js module for getting and setting HTTP(S) cookies. Cookies can be signed to prevent tampering, using Keygrip. It can be used with the built-in node.js HTTP library, or as Connect/Express middleware. I'm not sure if that lib is the best choice, but it did work back then. Other alternative may be https://github.com/maticzav/nookiesnext-cookies: Used to READ cookies universally (cannot write). Tiny little function for getting cookies on both client & server with next.js. This enables easy client-side and server-side rendering of pages that depend on cookies.
A cookies prop is available to all Page and Layout components (through the _app.tsx:render()).
universal-cookie looks promising and if you know about it,
you may ask yourself why we don't use it instead of one package for the client side, and another one for the server side.
Well, the answer is straightforward: It does not work. See ItsBenCodes/cookies#256
We've built our own UniversalCookiesManager utility class to deal with cookies in a universal way (same API on client/server sides).
It basically hides away the complexity, and allows for source code reusability.
Converts CSS text to a React Native stylesheet object.
Converts all number-like values to numbers, and string-like to strings.
Automatically converts indirect values to their React Native equivalents.
Used to dynamically convert CSS to React style object, for CSS rules coming from a data source (such as GraphCMS).
Currently used by GraphCMSAsset.tsx
Merges the enumerable properties of two or more objects deeply.
Used in many places to merge different objects together. Handles deeply nested objects.
graphql: Client for connecting to a GraphQL endpoint.graphql-tag: Helpful utilities for parsing GraphQL queries. Useful to write plain-text GraphQL query using thegqltag, that can be validated by other tools, such as JS GraphQL IntelliJ Plugin.- JS GraphQL IntelliJ Plugin: GraphQL language support for WebStorm, IntelliJ IDEA and other IDEs based on the IntelliJ Platform. The plugin is available using WebStorm directly. To install it, open your IDE "Settings", "Plugins", "Marketplace" and search for "GraphQL". But, it should be automatically made available by default. (through shared IDE config)
The usage of both gql and the IntelliJ GraphQL plugin is awesome, it allows to write GraphQL queries (see gql folder) and have auto-completion and validation from WebStorm itself.
To refresh the GraphQL spec, just run the .graphqlconfig file by opening it and run the stage you want to sync (usually staging).
TODO
Used to safely stringify JSON objects. Works even when they have circular dependencies
json-stringify-safe: Like JSON.stringify, but doesn't throw on circular references.
Use at your convenience. We weren't sure whether to use json-stringify-safe or safe-json-stringify and we made a wild choice here.
A modern JavaScript utility library delivering modularity, performance & extras.
We made the choice to import lodash packages one-by-one instead of loading the whole lodash lib directly.
We're not sure if it's better/easier/wiser. We suppose it should decrease the bundle size, but maybe it's natively handled by tree-shacking?
lodash.get: https://lodash.com/docs/4.17.15#getlodash.isempty: https://lodash.com/docs/4.17.15#isEmptylodash.isplainobject: https://lodash.com/docs/4.17.15#isPlainObjectlodash.map: https://lodash.com/docs/4.17.15#map ... And tons of other
We use plenty of utilities from lodash. Make sure read their documentation.
We also load each TS types one-by-one. One advantage of that is that we can decide not to load typings that do not work.
For instance, we tried using
@types/lodash.filterbut eventually removed it because it creates a mess that is hard to deal with. Typings may be wrong and breaks our tests, in such case it's nice to have the flexibility not to use them.
Next.js framework package and plugins/utilities.
next: Next.js framework package. See tutorial.next-cookies: See Cookiesnext-with-apollo: Apollo HOC for Next.js
React package and plugins/utilities.
react: React is a JavaScript library for creating user interfaces.react-apollo: React Apollo allows you to fetch data from your GraphQL server and use it in building complex and reactive UIs using the React framework. React Apollo may be used in any context that React may be used. In the browser, in React Native, or in Node.js when you want to do server-side rendering.react-dom: This package serves as the entry point to the DOM and server renderers for React. It is intended to be paired with the generic React package, which is shipped as react to npm.react-style-proptype: Validates style objects by ensuring the keys are valid css property names (in camelcase form).prop-types: Runtime type checking for React props and similar objects.
N.B:
reactandreact-dommust always use the same version.
Web Font Loader gives you added control when using linked fonts via @font-face.
It provides a common interface to loading fonts regardless of the source, then adds a standard set of events you may use to control the loading experience.
The Web Font Loader is able to load fonts from Google Fonts, Typekit, Fonts.com, and Fontdeck, as well as self-hosted web fonts. It is co-developed by Google and Typekit.
webfontloader: A logger for just about everything.
Peer-dependency of
@unly/utils-simple-logger
winston: A logger for just about everything.
TypeScript requires Typings to resolve types.
Those packages add additional types that allow TypeScript to resolve the related types, and allow for a better developer experience. Also, without some of those types, TS would fail to compile.
Sometimes, TS types are included in the same package as the main package, sometimes in a different package, such as for those below.
@types/jest: This package contains type definitions for Jest (https://jestjs.io/).@types/react: This package contains type definitions for React (http://facebook.github.io/react/).@types/webpack-env: Allow to use__non_webpack_require__with TypeScript.@typescript-eslint/eslint-plugin: ESLint plugin for TypeScript support .It is important that you use the same version number for@typescript-eslint/parserand@typescript-eslint/eslint-plugin.@typescript-eslint/parser: An ESLint custom parser which leverages TypeScript ESTree to allow for ESLint to lint TypeScript source code. ... lots more
Those dependencies are used only during the development and aren't shipped to the end-user.
They are meant to make the development process easier/faster.
Official packages from Zeit/Now, the company hosting our application
@now/node: Used as a dev dependency, it's useful to provide TypeScript support. Such as forimport { NowRequest, NowResponse } from '@now/node'.now: The Now CLI https://github.com/zeit/now https://www.npmjs.com/package/now@zeit/next-css: Additional Next configuration necessary to gain the ability toimport.cssfiles. Used to import other libs such asbootstrap.css.@zeit/next-source-maps: Generate source maps during production build in your Next.js project
Packages meant to help with the debug of the application
concurrently: Run multiple commands concurrently.cross-env: Run scripts that set and use environment variables across platforms.
Together, those two packages are used by the WebStorm "Debug" configuration. (top right)
Running the Debug configuration in debug mode allows to pause execution and use breakpoints.
Eslint helps us enforce code style and check for typos and errors during the development process
eslint: ESLint is a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code.eslint-plugin-react: React specific linting rules for ESLinteslint-plugin-react-hooks: This ESLint plugin enforces the Rules of Hooks. It is a part of the Hooks API for React.eslint-plugin-jest: ESLint plugin for Jesteslint-plugin-jsx-a11y: Static AST checker for accessibility rules on JSX elements.
Eslint rules are automatically used by WebStorm.
Eslint with TypeScript and JSX support was configured following this tutorial.
Run yarn lint to run the linter.
Jest is our test runner, it runs our tests to make sure we don't ship regressions to our end users
jest: Jest is a delightful JavaScript Testing Framework with a focus on simplicity.jest-extended: Additional Jest matchers. Provides additional built-in tests for ease of testing.react-test-renderer: This package provides an experimental React renderer that can be used to render React components to pure JavaScript objects, without depending on the DOM or a native mobile environment. Essentially, this package makes it easy to grab a snapshot of the "DOM tree" rendered by a React DOM or React Native component without using a browser or jsdom.ts-jest: TypeScript preprocessor with source map support for Jest that lets you use Jest to test projects written in TypeScript.
Known issues:
jest-emotion: Breaks tests
Cypress is a tool that helps performing end-to-end (E2E) tests that aim at testing the UI and the user workflows.
It is open source and free to use from the command line (doesn't count as Tests recording).
It also comes with a paid plan that provides a Dashboard, we use it with the Free plan, but it only allows 500 tests recordings per month.
Several utility scripts have been configured to help with E2E testing, each script takes an optional CYPRESS_STAGE environment variable, which defines the config file that will be used (development by default):
yarn e2e:open: Runs the test suite in a local browser (requiresyarn e2e:install), targets localhost development website. (uses cypress/config-development.json)yarn e2e:run: Runs the test suite in a local console, targets localhost development website. (uses cypress/config-development.json)
We used the following Cypress <> Next.js tutorial to get started. Note that our current installation doesn't provide test coverage. It's a bit harder to setup, here is a tutorial if ever needed.
N.B: Here is the documentation about the options available in the config files.
markdown-toc: Generate a markdown TOC (table of contents). Uses many dependencies, many of them outdated (handlebars) and containing security issues, but we don't care much about those as they aren't shipped in the build, but only present on the developer's local machine.version-bump-prompt: Used to make it easier to bump versions.