diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..28c7b405 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +build/ +coverage/ +dist/ +flow-typed/ +playwright-report/ +ljas-webpack/docs/ diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..d4e57783 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,14 @@ +module.exports = { + env: { + es2024: true, + node: true, + }, + extends: ['eslint:recommended', 'prettier'], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + root: true, + rules: {}, + overrides: [], +} diff --git a/.gitignore b/.gitignore index e47874aa..c2658d7d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1 @@ -build/ -coverage/ -flow-typed/ node_modules/ -.eslintcache -*.sublime-workspace -stats.*.json -yarn-error.log \ No newline at end of file diff --git a/.husky/install.mjs b/.husky/install.mjs new file mode 100644 index 00000000..e9bbbda3 --- /dev/null +++ b/.husky/install.mjs @@ -0,0 +1,6 @@ +// Skip Husky install in production and CI +if (process.env.NODE_ENV === 'production' || process.env.CI === 'true') { + process.exit(0) +} +const husky = (await import('husky')).default +console.log(husky()) diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000..7e154687 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npm run lint-staged diff --git a/.lintstagedrc b/.lintstagedrc new file mode 100644 index 00000000..fffe5e07 --- /dev/null +++ b/.lintstagedrc @@ -0,0 +1 @@ +{ "*": "prettier --ignore-unknown --write", "*.{js,jsx,ts,tsx}": "eslint" } diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..7dfe2487 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,9 @@ +build/ +coverage/ +dist/ +flow-typed/ +playwright-report/ +test-results/ +ljas-webpack/docs/ +*.sublime-workspace +package-lock.json diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..e7162d36 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "importOrder": ["", "^[./]"], + "importOrderSeparation": true, + "importOrderSortSpecifiers": true, + "plugins": ["@trivago/prettier-plugin-sort-imports"], + "semi": false, + "singleQuote": true, + "tabWidth": 4 +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..d8244449 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..f89ed5f1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.formatOnSave": true +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..c0babef4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,42 @@ +## 1.0.0 + +- Introduce Docker dev environments for all projects except for Electron-based projects +- Introduce PostgreSQL support with new Express + PostgreSQL starters: `express-postgres` & `react-express-postgres-ssr` +- Introduce dotenv ^16.4.5 +- Introduce Mock Service Worker ^2.2.2 +- Introduce Prettier 3.2.5 +- Introduce Prisma ^4.15.0 +- Introduce Playwright ^1.44.0 +- Introduce `electron-icon-maker` ^0.0.5 +- Replace Enzyme with React Testing Library ^14.2.1 +- Add DOM Testing Library ^9.3.4 for non-React frontend projects +- Replace Flow and PropTypes with TypeScript ~5.3.3 +- Replace React Hot Loader with React Refresh ^0.14.0 +- Replace Sublime Text support with Visual Studio support +- Drop support for Yarn +- Upgrade Babel to ^7.22.1 +- Upgrade Electron to 29.1.0 +- Upgrade ESLint to ^8.41.0 +- Upgrade Express to ^4.18.2 +- Upgrade Jest to ^29.5.0 +- Upgrade Node.js to ^20.9.0 +- Upgrade React to ^18.2.0 +- Upgrade SuperTest to ^6.3.3 +- Upgrade Stylelint to ^16.2.1 +- Upgrade webpack to ^5.85.0 +- Separate asset test and counter from `browser` project into its own examples: `asset-test` & `counter-react` +- Replace Node Sass with Dart Sass ~1.64.2 for `counter-react` +- Rewrite \*chan from `nodejs-ssr` project into its own `starchan` example +- Upgrade `react-redux` to ^8.1.3 for `starchan` +- Setup Redux Toolkit ^1.9.6 for `starchan` +- Upgrade React Router to ^6.16.0 for `starchan` +- Port `todolist-browser` project as `todo-list` example +- Create new vanilla JavaScript starter for browsers: `basic-browser` +- Create new vanilla JavaScript starter for desktops: `basic-electron` +- Create new vanilla JavaScript starter for Node.js: `basic-node` +- Create new Express + MongoDB starter: `express-mongo` +- Create new React starter for browsers: `react-browser` +- Create new React starter for desktops: `react-electron` +- Create new React + Express + MongoDB server-side rendering starter: `react-express-mongo-ssr` +- Create new desktop app example: `markdown-editor` +- Create new Express + PostgreSQL example: `notes-api` diff --git a/LICENSE b/LICENSE index 7d8e21de..87859308 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018-2019 Matthew Lean +Copyright (c) 2018–present Matthew Lean Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 3949fda7..06413bc5 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,79 @@ # Lean JavaScript Application Starter -Skip boilerplate setup and get straight to the code you care about for your next JavaScript application. -## Overview -### πŸš€ Simple Setup -Follow a few simple steps in the ["Getting Started" documentation](docs/getting_started.md) and get straight to coding! +**Lean JS App Starter (LJAS)** is a development environment designed to kickstart projects across browser, Node.js, and Electron platforms. It offers a modern developer experience, leveraging standard tools from the JavaScript ecosystem. LJAS's transparent and highly customizable configuration makes it easy to modify and meet the unique needs of your app. -### πŸŒ™ Consistent Codebase Across Multiple Environments -Consistent JavaScript standard, dependencies, and configuration no matter what environment you're building for. +**πŸŽ‰ Don't just code for browsers: build servers, desktop apps, CLI tools, and more** -| πŸ„β€ Web Browser | 🌐 Node.js | πŸ–₯️ Desktop | -|--------------------------------------------------------|--------------------------------------------------------|--------------------------------------------------------| -| [JavaScript (ES2015)](docs/javascript_features.md) | [JavaScript (ES2015)](docs/javascript_features.md) | [JavaScript (ES2015)](docs/javascript_features.md) | -| [Babel](https://babeljs.io) | [Babel](https://babeljs.io) | [Babel](https://babeljs.io) | -| [Flow](https://flow.org) | [Flow](https://flow.org) | [Flow](https://flow.org) | -| [Jest](https://jestjs.io) | [Jest](https://jestjs.io) | [Jest](https://jestjs.io) | -| [webpack](https://webpack.js.org) | [webpack](https://webpack.js.org) | [webpack](https://webpack.js.org) | -| [React](https://reactjs.org) | [React](https://reactjs.org) | [React](https://reactjs.org) | -| [Redux](https://redux.js.org) | [Redux](https://redux.js.org) | [Redux](https://redux.js.org) | -| [React Router](https://reacttraining.com/react-router) | [React Router](https://reacttraining.com/react-router) | [React Router](https://reacttraining.com/react-router) | -| [Sass](https://sass-lang.com) | [Sass](https://sass-lang.com) | [Sass](https://sass-lang.com) | -| | [Node.js](https://nodejs.org) | [Electron](https://electronjs.org) | -| | [Express](https://expressjs.com) | | -| | [MongoDB](https://mongodb.com) | | -| | [Mongoose](https://mongoosejs.com) | | +> Support for [TypeScript](https://typescriptlang.org), [Node.js](https://nodejs.org), [Electron](https://electronjs.org), [React](https://react.dev), and [Express](https://expressjs.com) servers that support React server-side rendering. -Future support for more environments and libraries are being considered. +**🐳 Docker development & testing environments** -### πŸ‘©β€πŸ’» Helpful Features for Development -#### Useful Tooling -Plugins, source maps, scripts, and tool integrations like Redux DevTools, Devtron, and many others are already setup for you to make debugging easier. +> Alternatively run the dev environment with [Docker](https://docker.com) to simplify onboarding and improve consistency for developers across macOS, Windows, and Linux. Use a specialized Docker test environment to improve the stability and trustworthiness of end-to-end test results. -Optionally use Flow, ESLint, and stylelint to help identify potential problems and produce better, safer code. +**πŸ§ͺ Robust testing environment** -#### Automatic Reloading & Hot Loading -No need to manually refresh, rebuild, and rerun your apps during development. Let a script automate all of that for you so you can see your changes as soon as possible. When coding with React, take advantage of hot loading so you can tweak components in real-time without refreshing and losing state. +> Write unit tests with [Jest](https://jestjs.io) and end-to-end tests with [Playwright](https://playwright.dev). Test frontends with [Testing Library](https://testing-library.com) and backend APIs with [SuperTest](https://github.com/ladjs/supertest). Mock network requests with [MSW](https://mswjs.io). -#### Server-Side Rendering Support -Render React components on the server and neatly integrate your browser and Node.js codebases together. +**πŸ—„οΈ Support for PostgreSQL & MongoDB** -### πŸ›οΈ Build For Production -Create a production ready build with one simple command. Minification and exclusion of unused code are all handled for you. Only the necessary JavaScript transformations/polyfills and CSS vendor prefixes for targeted browser versions are included. This ensures the build works everywhere you need while being the smallest size possible. +> Connect to [PostgreSQL](https://postgresql.org) and [MongoDB](https://mongodb.com) easily with [Prisma](https://prisma.io). Containerized databases are available so you aren't required to install databases natively on your machine. -### πŸ”§ Fully Customizable -If you ever need to change the configuration for anything, you can easily do so. The starting codebases are small, documented, easy to understand, and ready to adjust to all of your needs. +**⚑ Hot module replacement & auto-reloading** -## Get Started -### πŸ„β€ Web Browser -#### Download -If you want to build an app for web browsers, start with the [latest `browser` release](https://github.com/IsaacLean/lean-js-app-starter/releases). +> See changes reflected quickly in your app as soon as you save changes to your code. -#### Examples -You can find some example browser apps in the following branches: +**πŸ“¦ Optimized builds for production environments** -- [`todolist-browser`](https://github.com/IsaacLean/lean-js-app-starter/tree/todolist-browser): A todo list app. Connects with mock backend API. -- [`starchan-frontend`](https://github.com/IsaacLean/lean-js-app-starter/tree/starchan-frontend): The frontend app for an anonymous text board called *chan (pronounced star-chan). Requires connection with the *chan backend API on the [`nodejs` branch](https://github.com/IsaacLean/lean-js-app-starter/tree/nodejs). +> Generate optimized builds specialized for running in production environments. Output cross-browser compatible bundles for the web or OS-specific executable bundles for Linux, macOS, or Windows. -[Click here for documentation on building browser apps.](docs/envs/browser/README.md) +**🧼 Effortlessly maintain consistent code style** -### 🌐 Node.js -#### Downloads -If you want to build an app for Node.js, you have two options: +> Stop worrying about needing to remember rules or having disagreements with other team members about code styling. Just let [Prettier](https://prettier.io) and [ESLint](https://eslint.org) enforce code style for you. -- [`nodejs`](https://github.com/IsaacLean/lean-js-app-starter/tree/nodejs): An Express, MongoDB, and Mongoose starter project -- [`nodejs-ssr`](https://github.com/IsaacLean/lean-js-app-starter/tree/nodejs-ssr): An Express, MongoDB, and Mongoose starter project that supports server-side rendering for React +**⛷️ Smoothly move across multiple projects** -You can find the latest releases for these on the [releases page](https://github.com/IsaacLean/lean-js-app-starter/releases). +> The project setup and configuration consistency allows developers working on multiple LJAS-based projects to move back-and-forth between them easily. If you are familiar with one LJAS project then you will be comfortable working with all of them, regardless if the build target is a browser, Node.js, or Electron. -#### Examples -The Node.js example apps come with the base projects in the following branches: +**πŸ₯‡ Powered by the gold standards of the JS tooling ecosystem** -- [`nodejs`](https://github.com/IsaacLean/lean-js-app-starter/tree/nodejs): A REST API for an anonymous text board called *chan (pronounced star-chan). Optionally connects with the *chan frontend app on the [`starchan-frontend` branch](https://github.com/IsaacLean/lean-js-app-starter/tree/starchan-frontend). -- [`nodejs-ssr`](https://github.com/IsaacLean/lean-js-app-starter/tree/nodejs-ssr): A version of the *chan backend that supports server-side rendering of the frontend app. +> Nothing fancy and no surprises–the core tools are [webpack](https://webpack.js.org), [Babel](https://babeljs.io), and [ESLint](https://eslint.org). The configurations are intentionally designed to follow standard conventions so they are easy to understand and customize. -[Click here for documentation on building Node.js apps.](docs/envs/nodejs/README.md) +## Documentation -### πŸ–₯️ Desktop -#### Download -If you want to build an app for desktop, start with the [latest `desktop` release](https://github.com/IsaacLean/lean-js-app-starter/releases). +**πŸ€” Need help deciding if LJAS is right for your project?** -#### Examples -You can find an example desktop app in the following branch: +> Read the ["Motivation" document in the docs](./docs/motivation.md). -- [`todolist-desktop`](https://github.com/IsaacLean/lean-js-app-starter/tree/todolist-desktop): A todo list app ported from the browser targeted app on the [`todolist-browser` branch](https://github.com/IsaacLean/lean-js-app-starter/tree/todolist-browser). +**πŸ“– Learn about everything LJAS has to offer!** -[Click here for documentation on building desktop apps.](docs/envs/desktop/README.md) +> [Check out all of the documentation!](./docs) -### 🏊 Documentation -You can dive deeper into the project by reading the [documentation](docs/README.md) which is also included locally with each copy of the project in the [`docs/`](docs) folder. +## Getting Started + +LJAS offers several different **starter projects** with various different technologies pre-configured for you. Each one is designed for different targets like the browser or Node.js, and can also utilize different technologies such as JavaScript, TypeScript, React, or Express, etc. They are all designed as complete development environments that you can rely on out-of-the-box. + +Select a starter project below that fits your needs: + +| Starter Project Name | Description | JavaScript | TypeScript | +| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Basic Browser | A simple setup for a browser frontend built with just vanilla JavaScript or TypeScript. | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-browser) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-basic-browser_1-0-0.zip) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-browser-ts) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-basic-browser-ts_1-0-0.zip) | +| Basic Electron | A simple setup for an Electron desktop app built with just vanilla JavaScript or TypeScript. | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-electron) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-basic-electron_1-0-0.zip) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-electron-ts) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-basic-electron-ts_1-0-0.zip) | +| Basic Node.js | A simple setup for a Node.js app built with just vanilla JavaScript or TypeScript. | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-node) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-basic-node_1-0-0.zip) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-node-ts) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-basic-node-ts_1-0-0.zip) | +| Express + MongoDB | A web server that runs off Node.js, Express, MongoDB, and Prisma. | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/express-mongo) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-express-mongo_1-0-0.zip) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/express-mongo-ts) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-express-mongo-ts_1-0-0.zip) | +| Express + PostgreSQL | A web server that runs off Node.js, Express, PostgreSQL, and Prisma. | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/express-postgres) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-express-postgres_1-0-0.zip) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/express-postgres-ts) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-express-postgres-ts_1-0-0.zip) | +| React + Browser | A browser frontend that uses React. | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-browser) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-react-browser_1-0-0.zip) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-browser-ts) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-react-browser-ts_1-0-0.zip) | +| React + Electron | An Electron desktop app that uses React for its renderer processes. | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-electron) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-react-electron_1-0-0.zip) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-electron-ts) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-react-electron-ts_1-0-0.zip) | +| React + Express + MongoDB with SSR | A full-stack web app that runs off Node.js, Express, PostgreSQL, Prisma, and React. The backend supports React server-side rendering. | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-mongo-ssr) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-react-express-mongo-ssr_1-0-0.zip) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-mongo-ssr-ts) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-react-express-mongo-ssr-ts_1-0-0.zip) | +| React + Express + PostgreSQL with SSR | A full-stack web app that runs off Node.js, Express, PostgreSQL, Prisma, and React. The backend supports React server-side rendering. | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-postgres-ssr) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-react-express-postgres-ssr_1-0-0.zip) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-postgres-ssr-ts) / [Download](https://github.com/mattlean/lean-js-app-starter/releases/download/v1.0.0/ljas-react-express-postgres-ssr-ts_1-0-0.zip) | + +## Examples + +**Example projects** are built off of starter projects and act as a demonstration of how LJAS can used and adapted to different project requirements. + +You will be able to find projects like SPAs, REST APIs, desktop apps, and more. They can be handy if you need references for customized configurations that extend LJAS's functionality or some good ol' inspiration. + +[Take a look at the example projects in the `examples/` directory.](./examples) ## License -This open source project is licensed under the [MIT License](https://choosealicense.com/licenses/mit). \ No newline at end of file + +Lean JavaScript Application Starter is open source software [licensed as MIT](https://github.com/mattlean/lean-js-app-starter/blob/v1.0.0/LICENSE). diff --git a/docs/README.md b/docs/README.md index f13a3876..a90af4e6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,33 +1,75 @@ -# Lean JavaScript Application Starter Documentation +# LJAS Documentation + +Welcome to the documentation for **Lean JS App Starter (LJAS)**! + ## Table of Contents -* [Read Me](../README.md) -* [Motivation](motivation.md) -* [Getting Started](getting_started.md) -* [JavaScript Features](javascript_features.md) -* [Environments](envs/README.md) - * [Web Browser](envs/browser/README.md) - * [Getting Started](envs/browser/getting_started.md) - * [Developing](envs/browser/developing.md) - * [Building](envs/browser/building.md) - * [Dependencies](envs/browser/dependencies.md) - * [Configuration](envs/browser/configuration.md) - * [Examples](envs/browser/examples.md) - * [Node.js](envs/nodejs/README.md) - * [Node.js](envs/nodejs/nodejs/README.md) - * [Getting Started](envs/nodejs/nodejs/getting_started.md) - * [Developing](envs/nodejs/nodejs/developing.md) - * [Building](envs/nodejs/nodejs/building.md) - * [Dependencies](envs/nodejs/nodejs/dependencies.md) - * [Configuration](envs/nodejs/nodejs/configuration.md) - * [Examples](envs/nodejs/nodejs/examples.md) - * [Desktop](envs/desktop/README.md) - * [Getting Started](envs/desktop/getting_started.md) - * [Developing](envs/desktop/developing.md) - * [Building](envs/desktop/building.md) - * [Dependencies](envs/desktop/dependencies.md) - * [Configuration](envs/desktop/configuration.md) - * [Examples](envs/desktop/examples.md) -* [Tools](tools/README.md) - * [Postman](tools/postman.md) - * [Sublime Text](tools/sublime_text.md) -* [Resources](resources.md) \ No newline at end of file + +### [Motivation](./motivation.md) + +_Find out why you should consider using LJAS for your project._ + +--- + +### Setup + +_How to setup LJAS and start your project._ + +- [Getting Started](./setup/getting-started.md) +- [Code Editors](./setup/code-editors.md) +- [Git Pre-Commit Hooks](./setup/git-pre-commit-hooks.md) + +--- + +### **Developing** + +_How to develop with LJAS._ + +- [JavaScript & TypeScript](./developing/javascript-typescript.md) +- [Styling](./developing/styling.md) +- [Databases](./developing/databases/README.md) +- [Testing](./developing/testing.md) +- [Debugging](./developing/debugging.md) +- [Package Management](./developing/package-management.md) +- [React Server-Side Rendering](./developing/react-ssr.md) +- [Docker Environments](./developing/docker-environments.md) + +--- + +### [**Building**](./building.md) + +_How the build process works and how to create builds for production._ + +--- + +### **Configuration** + +_How the default configurations work and how to customize them._ + +- [`.env` File](./configuration/dotenv-file.md) +- [Babel](./configuration/babel.md) +- [Browserslist](./configuration/browserslist.md) +- [Docker](./configuration/docker.md) +- [electron-builder](./configuration/electron-builder.md) +- [ESLint](./configuration/eslint.md) +- [Husky & lint-staged](./configuration/husky-lint-staged.md) +- [Jest](./configuration/jest.md) +- [nodemon](./configuration/nodemon.md) +- [Playwright](./configuration/playwright.md) +- [Prettier](./configuration/prettier.md) +- [Prisma](./configuration/prisma.md) +- [Stylelint](./configuration/stylelint.md) +- [TypeScript](./configuration/typescript.md) +- [Visual Studio Code](./configuration/vscode.md) +- [webpack](./configuration/webpack.md) + +--- + +### [**Frequently Asked Questions**](./faq.md) + +_Answers to common questions that don't really fit anywhere else in the docs._ + +--- + +### [**Origins**](./origins.md) + +_The history of Lean JS App Starter._ diff --git a/docs/building.md b/docs/building.md new file mode 100644 index 00000000..9b3c4745 --- /dev/null +++ b/docs/building.md @@ -0,0 +1,124 @@ +# Building + +## Contents + +- [Overview](#overview) +- [Why use webpack still?](#why-use-webpack-still) +- [webpack Build Scripts](#webpack-build-scripts) +- [Build Targets](#build-targets) +- [Building Distributable Applications for Electron](#building-distributable-applications-for-electron) +- [Building Icons for Electron Applications](#building-icons-for-electron-applications) +- [Debugging the webpack Build Process](#debugging-the-wepback-build-process) +- [Troubleshooting](#troubleshooting) + +## Overview + +[webpack](https://webpack.js.org) is the core of the build process for all LJAS projects. When you run a `build` `package.json` script, it will start a webpack process which pull along other tools it needs as it progresses. When the build process is complete, it will produce the build files in the `build/` directory. + +When working with Electron-based projects, an additional step must be done to produce the distributable apps. This is explained in more detail in the ["Building Distributable Applications for Electron" section](#building-distributable-applications-for-electron). + +## Why use webpack still? + +At the time of writing, webpack is starting to fall out of fashion, but we still believe that it remains one of the best options for a JavaScript projects. Believe it or not, the time where setting up your development environment from scratch or using [Create React App](https://create-react-app.dev) was actually not too long ago (even though it may feel like an eternity in technology time already), and during the peak of this era, webpack was the number one build tool. LJAS originally was created in this webpack-era which is one of the reasons as to why we started with it, but we still intend to keep it because we think webpack's value still justifies itself in today's ecosystem. + +The most popular JavaScript-based dev environment is currently [Vite](https://vitejs.dev) which is undoubtably great for getting frontend web apps off the ground quickly as it hides the complexity around working with build tools. However, webpack stands its ground because there is still a strong use case where many users need full control of their build tools and require the ability to do things beyond out-of-the-box functionality with something like Vite. While Vite does offer you to go under-the-hood and customize its [esbuild](https://esbuild.github.io) and [Rollup](https://rollupjs.org) configurations, at that point we argue that webpack becomes the superior competitor as +it still has the most mature ecosystem that boasts an abundance of packages that can pretty much do everything you'd need along with a better selection of resources to search for and reference when compared to Vite, esbuild, and Rollup's resources. + +webpack is also generic so it can be used for any JavaScript project, not just frontend ones, which is how LJAS can target other platforms besides browsers. Outside of meta-frameworks, there isn't really a ubiquitous Vite or Create React App equivalent for Node.js apps. By applying webpack to Node.js, we can introduce all the bells and whistles frontend developers have been working with to the Node.js space while making non-browser projects easier for frontend developers to adjust to. + +## webpack Build Scripts + +There are several different build-related commands offered as `package.json` scripts that vary depending on which starter you're building off of, but two scripts that all projects have are: + +```console +npm run build +``` + +Create a development build in the `build/development/` directory. This process is automatically run for you in the `npm run dev` script. + +--- + +```console +npm run build:production +``` + +A variant of the `build` script that creates a production build in the `build/production/` directory. This is the build you should deploy to production. + +--- + +In addition to this, different starters will have other variant scripts available to you like: + +```console +npm run build:debug +``` + +Debug the webpack build process for development builds. Learn more about debugging webpack in the ["webpack build process with Google Chrome" section in the debugging document](./developing/debugging.md#webpack-build-process-with-google-chrome). + +--- + +```console +npm run build:stats +``` + +Run the webpack build process for a development build and output a `stats.json` file that can be analyzed using a build analysis tool. Learn more about webpack build analysis in the ["Build Analysis" chapter from the SurviveJS webpack book](https://survivejs.com/books/webpack/optimizing/build-analysis). + +--- + +You can always use `:production` in a script to control whether or not the build process should target the production environment. + +Starters that involve multiple webpack processes will also provide variant scripts that isolate specific ones. For example, in the [React + Express + PostgreSQL with Server-Side Rendering starter](../starters/react-express-postgres-ssr), the `build` script runs the frontend and backend webpack processes together. If you wanted to only run one of these processes, a `backend:` and `frontend:` prefix variants are available so you could run something like `npm run frontend:build` to execute the frontend webpack process by itself. + +## Build Targets + +[Browserslist](https://github.com/browserslist/browserslist) is used by multiple tools in the build process to determine what compatibility-related code should be included so the app can perform properly for the project's established build targets. Contrary to its name, Browserslist isn't just for controlling browser targets; it is used for controlling Node.js version targets as well. + +The following build process tools rely on Browserslist: + +- [webpack](https://webpack.js.org) +- [Babel](https://babeljs.io) +- [PostCSS](https://postcss.org) +- [Autoprefixer](https://github.com/postcss/autoprefixer) + +Edit the `.browserslistrc` file in the project's root directory to change build targets. For more information on configuring Browserslist, please read the [Browserslist configuration document](./configuration/browserslist.md). Always try to define build targets as precisely as possible as it will exclude unnecessary code for irrelevant platforms and keep your build size as small as possible. + +When working with Electron projects, you will also need to alter the webpack targets for the main process in `webpack/main.common.js` and the preload process in `webpack/preload.common.js`. + +## Building Distributable Applications for Electron + +LJAS uses [electron-builder](https://electron.build) to build distributable apps for macOS, Windows, and Linux. + +Before building distributable apps, you must have an existing webpack production build, so make sure that the `build:production` `package.json` script has been run beforehand. Once that's available, run the following: + +```console +npm run dist +``` + +This will initiate electron-builder which will use the build in the `build/production/` directory and produce a distributable app in the `dist/` directory. + +If you need to test the distributable app build process but you don't want to go through it completely, you can run the following script to generate the `dist/` directory without completely packaging the app: + +```console +npm run pack +``` + +To learn how to configure electron-builder, read the [electron-builder configuration document](./configuration/electron-builder.md). + +## Building Icons for Electron Applications + +You can convert an image into icons for your app using the `make-icons` `package.json` script. This script is an alias for [`electron-icon-maker`](https://github.com/jaretburkett/electron-icon-maker). + +Here is an example of this script converting a `.png` file: + +```console +npm run make-icons -- --input=/absolute/path/file.png --output=./relative/path/to/folder +``` + +## Debugging the wepback Build Process + +Please refer to the ["webpack Build Process with Google Chrome" section in the "Debugging" document](./developing/debugging.md#webpack-build-process-with-google-chrome). + +## Troubleshooting + +#### How do I clear babel-loader's cache? + +Delete the `node_modules/.cache/babel-loader` directory. diff --git a/docs/configuration/babel.md b/docs/configuration/babel.md new file mode 100644 index 00000000..86f10773 --- /dev/null +++ b/docs/configuration/babel.md @@ -0,0 +1,18 @@ +# Babel Configuration + +## Overview + +Most projects only have one [Babel config file](https://babeljs.io/docs/config-files) found in the project's root directory as `babel.config.js`. Some projects that involve multiple build targets that require different Babel settings will have multiple config files that are named with a different suffix depending on the build target. For example, the [React + Express + PostgreSQL with Server-Side Rendering starter](../../starters/react-express-postgres-ssr) has a backend Babel config file called `babel.backend.js` and a frontend Babel config file called `babel.frontend.js`. + +We currently use a JavaScript configuration file over other options like `.babelrc` or `babel.config.json` as it allows us to alter the configuration dynamically during runtime based on different conditions like the environment being used. + +## Learning Resources + +The following resources are from the [Babel docs](https://babeljs.io/docs): + +- [What is Babel?](https://babeljs.io/docs) + Get a basic overview of what Babel does. +- [Usage Guide](https://babeljs.io/docs/usage) + Learn the basics of configuring Babel by setting up a simple Babel configuration from scratch. +- [Configure Babel: JavaScript configuration files](https://babeljs.io/docs/configuration#javascript-configuration-files) + Learn how to format JavaScript configuration files and how to write dynamic configuration. diff --git a/docs/configuration/browserslist.md b/docs/configuration/browserslist.md new file mode 100644 index 00000000..c0a0ecbf --- /dev/null +++ b/docs/configuration/browserslist.md @@ -0,0 +1,22 @@ +# Browserslist Configuration + +## Overview + +All projects have a [Browserslist config file](https://github.com/browserslist/browserslist?tab=readme-ov-file#config-file) called `.browserslistrc` in the project's root directory. + +For Node.js-based projects, this config file determines which Node.js version is targeted. + +For Electron-based projects, this config file determines which Electron version is targeted. When this is changed you will also need to update the webpack targets in `webpack/main.common.js` and `webpack/preload.common.js` to match it. + +Other types of projects use [Browserslist environments](https://github.com/browserslist/browserslist?tab=readme-ov-file#configuring-for-different-environments) that change the build targets depending on the environment that the build is intended for. + +For browser-based projects, the config file determines which browsers are targeted for the development and production environments. + +For server-side rendering (SSR) supporting projects, the config file has one environment that determines the target Node.js version for the backend. The development and production environments determine the target browsers for the frontend. + +## Learning Resources + +- [Browserslist `README.md`](https://github.com/browserslist/browserslist) + Get a basic overview of what Browserslist is and how to configure it. +- [`browsersl.ist`](https://browsersl.ist) + A useful tool to test the validity and targets for Browserslist queries. diff --git a/docs/configuration/docker.md b/docs/configuration/docker.md new file mode 100644 index 00000000..f53739d6 --- /dev/null +++ b/docs/configuration/docker.md @@ -0,0 +1,27 @@ +# Docker Configuration + +## Overview + +All projects except for Electron-based ones will offer a Docker dev environment that is handled by files located in the project's root directory. + +The development environment is configured through the `Dockerfile` which is used to assemble the image for the application container and the `docker-compose.yml` file which is used to configure Docker Compose. Docker Compose is always setup as long as a Docker environment is supported, even if the project only involves one container, as it simplifies terminal commands and makes them consistent across projects. + +If the project involves a database, a `db.Dockerfile` will be used for assembling the image for the database container. When this file is present, Docker Compose will be configured so the database and app containers will be able to communicate with one another. + +If the project is frontend-related, a Docker end-to-end (E2E) test environment will also be provided and be configurable through its own `e2e.Dockerfile` and `docker-compose.e2e.yml` file. + +All Docker environments use a `.dockerignore` file which determines which files and directories will be ignored during the image build process. + +## Learning Resources + +The following resources are beginner-level guides from the [Docker docs](https://docs.docker.com) that will teach you how to configure Docker. + +- [Building images: Understanding image layers](https://docs.docker.com/get-started/docker-concepts/building-images/understanding-image-layers) +- [Building images: Writing a Dockerfile](https://docs.docker.com/get-started/docker-concepts/building-images/writing-a-dockerfile) +- [Building images: Build, tag, and publish an image](https://docs.docker.com/get-started/docker-concepts/building-images/build-tag-and-publish-an-image) +- [Running containers: Publishing and exposing ports](https://docs.docker.com/get-started/docker-concepts/running-containers/publishing-ports) +- [Running containers: Overriding container defaults](https://docs.docker.com/get-started/docker-concepts/running-containers/overriding-container-defaults) +- [Running containers: Persisting container data](https://docs.docker.com/get-started/docker-concepts/running-containers/persisting-container-data) +- [Running containers: Sharing local files with containers](https://docs.docker.com/get-started/docker-concepts/running-containers/sharing-local-files) +- [Running containers: Multi-container applications](https://docs.docker.com/get-started/docker-concepts/running-containers/multi-container-applications) +- [Node.js language-specific guide](https://docs.docker.com/guides/nodejs) diff --git a/docs/configuration/dotenv-file.md b/docs/configuration/dotenv-file.md new file mode 100644 index 00000000..de3d531f --- /dev/null +++ b/docs/configuration/dotenv-file.md @@ -0,0 +1,9 @@ +# `.env` File + +Instead of manually assigning environment variables through terminal commands, LJAS supports the definition of environment variables through a `.env` file using the [`dotenv` package](https://github.com/motdotla/dotenv). + +The `.env` file does not exist by default, so you will need to create a new one when starting a new LJAS project. There are a few ways to do so which is gone over in the "Getting Started" section of your project's `README.md`, but a simple way to create one is to just copy the `.env.example` file and paste it as `.env` in the project's root directory. + +Note that the `.env` file should never be committed to version control or shared as it could potentially contain private secrets. It is ignored by default in the `.gitignore` file in the project's root directory. + +For more information on configuring and working with the `.env` file, please read the [`dotenv`'s `README.md`](https://github.com/motdotla/dotenv). diff --git a/docs/configuration/electron-builder.md b/docs/configuration/electron-builder.md new file mode 100644 index 00000000..664c013c --- /dev/null +++ b/docs/configuration/electron-builder.md @@ -0,0 +1,10 @@ +# electron-builder + +## Overview + +All Electron-based projects have their [electron-builder configuration](https://electron.build/configuration.html) in a config file called `electron-builder.yml` in the project's root directory. + +## Learning Resources + +- [electron-builder Docs: Quick Setup Guide](https://electron.build/#quick-setup-guide) + Learn the basics of configuring electron-builder by setting up a simple electron-builder configuration from scratch. diff --git a/docs/configuration/eslint.md b/docs/configuration/eslint.md new file mode 100644 index 00000000..caf275e8 --- /dev/null +++ b/docs/configuration/eslint.md @@ -0,0 +1,14 @@ +# ESLint Configuration + +## Overview + +All projects have one ESLint config file found in the project's root directory as `.eslintrc.js`. The [`overrides`](https://eslint.org/docs/latest/use/configure/configuration-files-deprecated#how-do-overrides-work) property specifies subconfigurations specific to certain directories. For example, all projects have their default ESLint configuration, but then there will be a specific override subconfiguration for Jest which will import plugins like [`eslint-plugin-jest`](https://github.com/jest-community/eslint-plugin-jest) which are unnecessary for other directories in the codebase. + +All projects also have a `.eslintignore` file in the project's root directory which tells ESLint which files and directories should be skipped when linting. + +Note that we currently use the [deprecated config system](https://eslint.org/docs/latest/use/configure/configuration-files-deprecated) which will be changed when we updated to ESLint v9.x in a future LJAS version. + +## Learning Resources + +- [Getting Started with ESLint](https://eslint.org/docs/v8.x/use/getting-started) + Learn the basics of configuring ESLint by setting up a simple ESLint configuration from scratch. diff --git a/docs/configuration/husky-lint-staged.md b/docs/configuration/husky-lint-staged.md new file mode 100644 index 00000000..854a785d --- /dev/null +++ b/docs/configuration/husky-lint-staged.md @@ -0,0 +1,12 @@ +# Husky & lint-staged Configuration + +## Overview + +Husky configuration can be found in `.husky/pre-commit` which simply runs the `lint-staged` `package.json` script. The lint-staged configuration can be found in the project's root directory as the `.lintstagedrc` file. + +## Learning Resources + +- [Husky Docs: Get Started](https://typicode.github.io/husky/get-started.html) + Learn how to setup Husky. +- [lint-staged `README.md`](https://github.com/lint-staged/lint-staged) + Learn the basics of configuring lint-staged by setting it up and viewing a couple of examples. diff --git a/docs/configuration/jest.md b/docs/configuration/jest.md new file mode 100644 index 00000000..c73350bd --- /dev/null +++ b/docs/configuration/jest.md @@ -0,0 +1,16 @@ +# Jest Configuration + +## Overview + +All projects have a `jest.config.js` file in the project's root directory that acts as Jest's main [configuration file](https://jestjs.io/docs/configuration). + +The [`setupFilesAfterEnv` option](https://jestjs.io/docs/configuration#setupfilesafterenv-array) within it is configured to load the `jest.setup.js` file (or the `jest.setup.ts` file if the project uses TypeScript) which is responsible for executing setup code before each test file executes. This is where packages like [`dotenv`](https://github.com/motdotla/dotenv) or [Testing Library's `jest-dom`](https://testing-library.com/docs/ecosystem-jest-dom) is setup. + +Frontend-related projects will mock styles and graphic assets in its corresponding source root directory under the `__mocks__/` directory. + +When working in TypeScript-based projects, [`ts-jest`](https://kulshekhar.github.io/ts-jest) is used to enable TypeScript support with Jest. + +## Learning Resources + +- [Jest Docs: Getting Started](https://jestjs.io/docs/getting-started) + Learn the basics of configuring Jest by setting up a simple Jest configuration from scratch. diff --git a/docs/configuration/nodemon.md b/docs/configuration/nodemon.md new file mode 100644 index 00000000..f4600e60 --- /dev/null +++ b/docs/configuration/nodemon.md @@ -0,0 +1,34 @@ +# nodemon Configuration + +## Overview + +Every project may have a different mix of [nodemon configuration files](https://github.com/remy/nodemon?tab=readme-ov-file#config-files), but each file falls into one of the following two categories: + +### 1. Configuration File Watch + +These nodemon config files are responsible for restarting the webpack build processes when changes to configuration files occur. They are used for some `build:watch` and `dev` `package.json` scripts depending on if the script is related to a Node.js or browser context (e.g., `npm run backend:build:watch`, `npm run frontend:dev`, `npm run main:build:watch`, `npm run renderer:dev`): + +- `nodemon.json` +- `nodemon.backend.json` +- `nodemon.frontend.json` +- `nodemon.main.json` +- `nodemon.preload.json` +- `nodemon.renderer.json` + +This type of nodemon config file works in tandem with webpack, so nodemon isn't actually responsible for watching for changes in the app's source code (i.e. all the code in the `src/` directory). That's webpack's job. + +Instead, nodemon watches files outside of webpack's jurisdiction like `package.json`, nodemon config files, and webpack config files (i.e. anything outside of the `src/` directory) that should still affect the build in some way. + +### 2. Application Auto Reload + +These nodemon config files are responsible for restarting the app process when new builds are found (i.e. changes to the `build/` directory) which essentially enables auto reloading. They are used for the `start:debug` and `dev:production` `package.json` scripts: + +- `nodemon.development.json` +- `nodemon.production.json` + +Note that `nodemon.production.json` is not actually used for production deployments. It is only used for debugging production builds. + +## Learning Resources + +- [nodemon `README.md`: Usage](https://github.com/remy/nodemon?tab=readme-ov-file#usage) + Learn how nodemon works. diff --git a/docs/configuration/playwright.md b/docs/configuration/playwright.md new file mode 100644 index 00000000..e60c1ac3 --- /dev/null +++ b/docs/configuration/playwright.md @@ -0,0 +1,12 @@ +# Playwright Configuration + +## Overview + +All frontend-related projects have a [Playwright config](https://playwright.dev/docs/test-configuration) called `playwright.config.js` in the project's root directory. + +It mostly uses default settings except that it sets the [`testDir` property](https://playwright.dev/docs/api/class-testconfig#test-config-test-dir) to `./src/playwright`. For Electron-based projects, the [`projects` property](https://playwright.dev/docs/api/class-testconfig#test-config-projects) reduces the browser to only Chromium as that is the only browser needed for Electron. + +## Learning Resources + +- [Playwright Docs: Getting Started - Installation](https://playwright.dev/docs/intro) + Learn the basics of Playwright configuration by installing Playwright. diff --git a/docs/configuration/prettier.md b/docs/configuration/prettier.md new file mode 100644 index 00000000..883b69de --- /dev/null +++ b/docs/configuration/prettier.md @@ -0,0 +1,16 @@ +# Prettier Configuration + +## Overview + +The [Prettier configuration file](https://prettier.io/docs/en/configuration) can be found as the `.prettierrc.json` file in the project's root directory. + +Prettier's [exclusion of files](https://prettier.io/docs/en/ignore) is controlled through the `.prettierignore` and `.gitignore` files in the project's root directory. + +## Sort Imports Plugin + +By default, LJAS sets up [a plugin for Prettier that sorts import declarations which you can learn more about in its `README.md`](https://github.com/trivago/prettier-plugin-sort-imports). + +## Learning Resources + +- [Prettier Docs: Install](https://prettier.io/docs/en/install.html) + Learn the basics of configuring Prettier by setting up a simple Prettier configuration from scratch. diff --git a/docs/configuration/prisma.md b/docs/configuration/prisma.md new file mode 100644 index 00000000..95304c49 --- /dev/null +++ b/docs/configuration/prisma.md @@ -0,0 +1,16 @@ +# Prisma Configuration + +## Overview + +All database-based projects will have their Prisma configuration found in the `prisma/` directory. Its contents will vary depending on the database you're working with, but the main file you'll probably work with the most is the [Prisma Schema](https://prisma.io/docs/orm/prisma-schema/overview) named `schema.prisma`. + +## `DATABASE_URL` Environment Variable + +By default, the Prisma Schema will look for the `DATABASE_URL` environment variable which defines the [connection string](https://pris.ly/d/connection-strings). We recommend assigning this through the `.env` file which you can learn more about in the [`.env` File document](./dotenv-file.md). + +## Learning Resources + +- [Set up Prisma ORM: Start from scratch - Relational databases](https://prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases-typescript-postgresql) + Learn the basics of configuring and using Prisma by setting it up with a relational database from scratch. +- [Set up Prisma ORM: Start from scratch - MongoDB](https://prisma.io/docs/getting-started/setup-prisma/start-from-scratch/mongodb-typescript-mongodb) + Learn the basics of configuring and using Prisma by setting it up with MongoDB from scratch. diff --git a/docs/configuration/stylelint.md b/docs/configuration/stylelint.md new file mode 100644 index 00000000..12fde2f0 --- /dev/null +++ b/docs/configuration/stylelint.md @@ -0,0 +1,46 @@ +# Stylelint Configuration + +## Overview + +All frontend related projects have a [Stylelint config file](https://stylelint.io/user-guide/configure) called `.stylelintrc.json` in the project's root directory. Alongside that file is also a `.stylelintignore` file which is responsible for telling Stylelint which files and directories should be skipped while linting. + +## Adding Support for Sass + +The frontend starter projects only support CSS by default since that is the fundamental stylesheet language, but it doesn't take much to setup [Sass](https://sass-lang.com). + +Install [Dart Sass](https://github.com/sass/dart-sass) and [sass-loader](https://webpack.js.org/loaders/sass-loader) with the following command: + +```console +npm install sass@~1.64.2 sass-loader@^13.3.2 +``` + +Next, you will need to replace the CSS-related [`ljas-webpack`](../../ljas-webpack) config parts in the frontend webpack configuration with the equivalent Sass config parts. + +So, for example, in a frontend webpack development config file, you'd replace `injectCss` with `injectSass`. Then in a frontend webpack production config file, you'd replace `buildPrefixedCss` with `buildPrefixedSass`. + +Finally, the last thing to do is configure Stylelint to cover `.scss` files. Install the standard Stylelint SCSS config with the following command: + +```console +npm install stylelint-config-standard-scss@^11.0.0 --save-dev +``` + +Then update `.stylelintrc.json` to include `stylelint-config-standard-scss` in the `extends` property like so: + +```json +{ "extends": ["stylelint-config-standard-scss"] } +``` + +You should be able to handle `.sass` and `.scss` files in your JavaScript or TypeScript code now. + +Although everything should be working, you should also update the `lint:styles` `package.json` script to look for `.sass` and `.scss` files using something like this command: + +``` +"lint:styles": "stylelint \"src/**/*.{sass,scss}\"", +``` + +You can find examples of Sass being configured in the [Counter](../../examples/counter) and [Counter, React version](../../examples/counter-react) examples. + +## Learning Resources + +- [Stylelint Docs: Getting Started](https://stylelint.io/user-guide/get-started) + Learn the basics of configuring Stylelint by setting up a simple Stylelint configuration from scratch. diff --git a/docs/configuration/typescript.md b/docs/configuration/typescript.md new file mode 100644 index 00000000..953e515c --- /dev/null +++ b/docs/configuration/typescript.md @@ -0,0 +1,20 @@ +# TypeScript Configuration + +## Overview + +TypeScript projects all have a `tsconfig.json` file in their project's root directory which is responsible for configuring type checking during development. + +In addition to the standard `tsconfig.json`, there are more TypeScript config files specifically used for webpack processes. If there is just one webpack process, then there will only be a `tsconfig.build.json`. + +If there are multiple webpack processes involved, then there will be multiple config files, each with a different suffix related to its build target. For example, the [React + Express + PostgreSQL with Server-Side Rendering starter](../../starters/react-express-postgres-ssr) has a `tsconfig.build.backend.json` and a `tsconfig.build.frontend.json`. + +These webpack-specific TypeScript config files extend `tsconfig.json` and override some of the options set in it so we can type check everything during development, but still skip type checking irrelevant files for the build (i.e. tests). + +Note that the [`noEmit` option](https://typescriptlang.org/tsconfig/#noEmit) is enabled as LJAS does not use `tsc` to compile TypeScript files. Instead, the webpack build process uses Babel to compile everything including TypeScript. [We explain why we do this in the FAQ document.](../faq.md#why-use-babel-over-the-official-typescript-compiler) + +## Learning Resources + +- [Download TypeScript](https://typescriptlang.org/download) + Learn how to download, install, and use the TypeScript compiler. +- [Project Configuration: What is a tsconfig.json](https://typescriptlang.org/docs/handbook/tsconfig-json.html) + Learn what `tsconfig.json` does and how to extend a base configuration. diff --git a/docs/configuration/vscode.md b/docs/configuration/vscode.md new file mode 100644 index 00000000..0f56ce66 --- /dev/null +++ b/docs/configuration/vscode.md @@ -0,0 +1,8 @@ +# Visual Studio Code Configuration + +You can find all the existing [configurations for the Visual Studio Code workspace](https://code.visualstudio.com/docs/getstarted/settings#_workspace-settings) in the `.vscode/` directory which will contain the following files: + +- `settings.json`: Persisted and shareable editor settings + - `editor.formatOnSave`: This setting is set to `true` by default so [Prettier](https://prettier.io) can format code every time you save. If you want to disable this functionality, set this option to `false`. +- `launch.json`: Run and debug settings +- `extensions.json`: Determines which extensions show up as recommended in the extensions view diff --git a/docs/configuration/webpack.md b/docs/configuration/webpack.md new file mode 100644 index 00000000..9b747f91 --- /dev/null +++ b/docs/configuration/webpack.md @@ -0,0 +1,29 @@ +# webpack Configuration + +## Overview + +Most webpack configurations you'll come across on the web will cram all of their configuration in one huge `webpack.config.js` file, but as your configuration grows in complexity and size, stuffing everything into one file can hurt readability and maintainability. This is why LJAS splits its webpack config across multiple files and then uses [`webpack-merge`](https://npmjs.com/package/webpack-merge) to combine the relevant config files for the given environment. + +Every webpack process is split into four types of files: + +- `*.config.js`: The entry point into the webpack process's configuration. +- `*.development.js`: Configurations specifically for the development build. +- `*.production.js`: Configurations specifically for the production build. +- `*.common.js`: Configurations that are common for all builds. + +If there is only one webpack process in the project's build process, you will find the webpack config files in the project's root directory prefixed with `webpack`, e.g. `webpack.config.js`, `webpack.production.js`, etc. + +If the project's build process involves multiple webpack processes, each one will have its own set of four config files as described above in the `webpack/` directory. What differentiates each set of config files will be its prefix which will correspond to the webpack process it's for. For example, the [React + Express + PostgreSQL with Server-Side Rendering starter](../../starters/react-express-postgres-ssr) has two webpack processes: one for the backend and one for the frontend. The set of config files relevant to the backend will be prefixed with `backend`, and the frontend will have its own equivalent prefixed with `frontend`. + +LJAS also uses webpack configuration parts from our own package called [`ljas-webpack`](../../ljas-webpack). This allows us to easily reuse common webpack config code across multiple projects. [If you would like to learn more about `webpack-merge` and `ljas-webpack`, we go more into detail on how it all works together in `ljas-webpack`'s `README.md`.](../../ljas-webpack/README.md) + +## Learning Resources + +- [webpack's "Getting Started" guide](https://webpack.js.org/guides/getting-started) + Learn the basics of webpack from the "Getting Started" guide in the webpack docs. +- [webpack's "Production" guide](https://webpack.js.org/guides/production) + Learn about webpack's best practices and write a configuration for production. +- [SurviveJS webpack book](https://survivejs.com/books/webpack) + A free book on webpack that starts from the basics and goes all the way to advanced techniques that will teach you how to get the most out of webpack. It was written by one of the founders of the webpack core team, [Juho VepsΓ€lΓ€inen](https://survivejs.com/about-me). + - ["Composing Configuration" chapter](https://survivejs.com/webpack/developing/composing-configuration) + This particular chapter is the most important one in the book because this is where LJAS's webpack configuration composition strategy comes from. It explains what webpack config parts are and how to compose webpack configs with `webpack-merge`. diff --git a/docs/developing/databases/README.md b/docs/developing/databases/README.md new file mode 100644 index 00000000..28bc8c5b --- /dev/null +++ b/docs/developing/databases/README.md @@ -0,0 +1,134 @@ +# Databases + +LJAS supports [PostgreSQL](https://postgresql.org) and [MongoDB](https://mongodb.com) with [Prisma](https://prisma.io). + +This document is only relevant to the following Prisma-related starter projects: + +| Starter Project Name | JavaScript | TypeScript | +| ------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| Express + MongoDB | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/express-mongo) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/express-mongo-ts) | +| Express + PostgreSQL | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/express-postgres) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/express-postgres-ts) | +| React + Express + MongoDB with SSR | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-mongo-ssr) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-mongo-ssr-ts) | +| React + Express + PostgreSQL with SSR | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-postgres-ssr) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-postgres-ssr-ts) | + +## Contents + +- [Why Prisma?](#why-prisma) +- [Learning Resources](#learning-resources) +- [Prisma CLI](#prisma-cli) +- [Prisma Studio](#prisma-studio) +- [Connecting to Docker Databases Through a Terminal](#connecting-to-docker-databases-through-a-terminal) +- [Connecting a Natively Running App with a Containerized Database](#connecting-a-natively-running-app-with-a-containerized-database) +- [Prisma Configuration](#prisma-configuration) +- [Examples](#examples) +- [Frequently Asked Questions](#frequently-asked-questions-faq) + +## Why Prisma? + +We decided to use Prisma primarily because of the following: + +- [Object-relational mapping (ORM) with support for both PostgreSQL & MongoDB](https://prisma.io/docs/orm/overview/databases) +- [Generated types for TypeScript derived from models](https://prisma.io/docs/orm/prisma-client/type-safety#what-are-generated-types) +- [Support for migrations](https://prisma.io/docs/orm/prisma-migrate/understanding-prisma-migrate/overview) + +The Prisma docs go over other good reasons to use their ORM in their [introduction docs](https://prisma.io/docs/orm/overview/introduction/why-prisma). + +## Learning Resources + +### PostgreSQL + +- [PostgreSQL tutorial](https://postgresql.org/docs/current/tutorial.html) + Learn the basic concepts for PostgreSQL and how to execute queries with `psql`. +- [Prisma's relational databases guide](https://prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases-typescript-postgresql) + Learn the basics for Prisma with PostgreSQL. + +### MongoDB + +- [MongoDB manual introduction](https://mongodb.com/docs/manual/introduction) + Learn the basic concepts for MongoDB. +- [`mongo` shell docs](https://mongodb.com/docs/v4.4/mongo) + Learn how to execute queries with the `mongo` shell. +- [Prisma's MongoDB guide](https://prisma.io/docs/getting-started/setup-prisma/start-from-scratch/mongodb-typescript-mongodb) + Learn the basics for Prisma with MongoDB. + +## Prisma CLI + +The [Prisma command line interface (CLI)](https://prisma.io/docs/orm/tools/prisma-cli) is the primary way of interacting with Prisma. It is used to do various things like make migrations and generate the Prisma Client. + +The Prisma CLI can be accessed through the `prisma` `package.json` script: + +```console +npm run prisma +``` + +## Prisma Studio + +[Prisma Studio](https://prisma.io/studio) is a tool that lets you explore and manipulate the data in your database through a UI in the browser. It is an alternative to using something like `psql` or `mongo` that works in a terminal. + +To start it, run the following `package.json` script: + +```console +npm run prisma:studio +``` + +## Connecting to Docker Databases Through a Terminal + +To learn how to connect to Docker databases through a terminal, read the ["Connecting to Docker Databases Through a Terminal" section in the "Docker Environments" document](../docker-environments.md#connecting-to-docker-databases-through-a-terminal). + +## Connecting a Natively Running App with a Containerized Database + +Some may prefer running their app natively while connecting it to the database running in a container. This creates what we refer to as a hybrid dev environment and can be a great option for those who want to see improved performance for app development but still want all of the conveniences that come with running the database in the Docker dev environment. + +To set this up, first remove the `app` service and its dependent volumes in the Docker Compose config file. You can reference [an example that applies these changes to the **Express + PostgreSQL starter's** `docker-compose.yml` file.](./docker-compose.hybrid-example.yml) + +After that, all you need to do is modify the `DATABASE_URL` environment variable in the `.env` file to the appropriate connection string so Prisma can connect to the database. + +If you're working with unchanged values from the initial setup, then all you need to do is change `db` in the existing connection string to `localhost`. + +Using the [**Express + PostgresSQL starter's** `.env` file](../../../starters/express-postgres/.env.example) as an example, you would modify this... + +``` +DATABASE_URL="postgresql://postgres:password@db:5432/postgres?schema=public" +``` + +...to this... + +``` +DATABASE_URL="postgresql://postgres:password@localhost:5432/postgres?schema=public" +``` + +## Prisma Configuration + +Read the [Prisma configuration document](../../configuration/prisma.md) to learn how it is configured and how to customize it yourself. + +## Examples + +- [Notes API](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/examples/notes-api): REST API that uses PostgreSQL & Prisma +- [\*chan](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/examples/starchan): Server-side rendered React app that uses MongoDB & Prisma + +## Frequently Asked Questions (FAQ) + +### Questions + +- [How do I fix type errors encountered with Prisma?](#how-do-i-fix-type-errors-encountered-with-prisma) +- [Why do you still use MongoDB 4 and not a newer version?](#why-do-you-still-use-mongodb-4-and-not-a-newer-version) + +--- + +#### How do I fix type errors encountered with Prisma? + +You may encounter a case where TypeScript is throwing type errors with your Prisma-related code when it shouldn't. If this is happening, try running [`prisma generate`](https://prisma.io/docs/orm/prisma-client/setup-and-configuration/generating-prisma-client) to generate the [Prisma Client](https://prisma.io/docs/orm/prisma-client/setup-and-configuration/introduction). + +You can use the `prisma` `package.json` script to do this: + +```console +npm run prisma generate +``` + +Note that if you ever make any changes to the Prisma schema, you must re-run `prisma generate` to update the Prisma Client as well. + +--- + +#### Why do you still use MongoDB 4 and not a newer version? + +At the moment the [official Prisma example uses a MongoDB 4 base image](https://github.com/prisma/prisma/blob/main/docker/mongodb_replica/Dockerfile) so we follow and do the same. diff --git a/docs/developing/databases/docker-compose.hybrid-example.yml b/docs/developing/databases/docker-compose.hybrid-example.yml new file mode 100644 index 00000000..cd92b6b7 --- /dev/null +++ b/docs/developing/databases/docker-compose.hybrid-example.yml @@ -0,0 +1,46 @@ +# This Docker Compose configuration file is based on the express-postgres starter. +# It comments out the lines related to the app service to allow for the usage of a +# hybrid Docker development environment. +version: '3.8' +name: ljas-hybrid-example +services: + db: + build: + dockerfile: db.Dockerfile + image: ljas-hybrid-example-db + container_name: ljas-hybrid-example-db + restart: always + ports: + - '${POSTGRES_PORT}:${POSTGRES_PORT}' + env_file: .env + command: '-p ${POSTGRES_PORT}' + volumes: + - ljas-hybrid-example-db-data:/var/lib/postgresql/data + healthcheck: + test: + [ + 'CMD-SHELL', + 'pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER} -p ${POSTGRES_PORT}', + ] + interval: 10s + timeout: 5s + retries: 5 + # app: + # build: . + # image: ljas-hybrid-example + # container_name: ljas-hybrid-example + # depends_on: + # db: + # condition: service_healthy + # restart: always + # ports: + # - '${PORT_EXPRESS}:${PORT_EXPRESS}' + # - '5555:5555' # Exposes Prisma Studio. Also defined in the "prisma:studio" package.json script. + # - '9229:9229' # Exposes Node.js debugger. Also defined in the "start:debug" package.json script. + # - '9230:9230' # Exposes Jest debugger. Also defined in the "test:debug" package.json script. + # - '9231:9231' # Exposes webpack debugger. Also defined in the build debug package.json scripts. + # volumes: + # - .:/code + # - /code/node_modules +volumes: + ljas-hybrid-example-db-data: diff --git a/docs/developing/debugging.md b/docs/developing/debugging.md new file mode 100644 index 00000000..c005a87a --- /dev/null +++ b/docs/developing/debugging.md @@ -0,0 +1,95 @@ +# Debugging + +## Contents + +- [Node.js Applications & Electron Main Processes with Visual Studio Code](#nodejs-applications--electron-main-processes-with-visual-studio-code) +- [Frontend Applications with Google Chrome](#frontend-applications-with-google-chrome) +- [Jest Tests with Visual Studio Code](#jest-tests-with-visual-studio-code) +- [Playwright Tests with Visual Studio Code Extension](#playwright-tests-with-visual-studio-code-extension) +- [Playwright Tests with Playwright Inspector](#playwright-tests-with-playwright-inspector) +- [webpack build process with Google Chrome](#webpack-build-process-with-google-chrome) + +--- + +## Node.js Applications & Electron Main Processes with Visual Studio Code + +In VS Code, open the run and debug view by clicking on its icon in the activity bar on the side of the editor. The icon looks like this: +![VS Code run and debug view icon](../images/vs-code-run-and-debug-icon.png) + +Then select one of the following options in its configuration dropdown: + +### 1. "Attach to Running App" or "Attach to Running Main Process" + +Select this option if you already have the Node.js app or main process running in debug mode and hit the green play button to start debugging. + +You can run the app/main process in debug mode using the `start:debug` `package.json` script. You can alternatively use `dev` `package.json` script as well since under-the-hood it uses the `start:debug` script. + +Note that for Node.js apps, the Docker dev environment already runs the app in debug mode by default. Therefore you can skip straight to using this option in the dropdown after the container's app is running. + +### 2. "Launch & Attach to App" or "Launch & Attach to Main Process" + +Select this option if the Node.js app/main process is not currently running and hit the green play button to start debugging. This will start the app/process in debug mode. + +Note that this does require a build to already exist, so if one isn't already available you will need to run the build process once before using this option. + +[Learn more about debugging with VS Code through its "Debugging" user guide.](https://code.visualstudio.com/docs/editor/debugging) + +## Frontend Applications with Google Chrome + +Simply open up the app in Google Chrome and open up Chrome DevTools. + +[Learn more about debugging with Chrome DevTools through its "Debug JavaScript" tutorial.](https://developer.chrome.com/docs/devtools/javascript) + +## Jest Tests with Visual Studio Code + +In VS Code, open the run and debug view by clicking on its icon in the activity bar on the side of the editor. The icon looks like this: +![VS Code run and debug view icon](../images/vs-code-run-and-debug-icon.png) + +Then select one of the following options in its configuration dropdown: + +### 1. "Attach to Running Jest" + +Select this option if you already have Jest tests running in debug mode and hit the green play button to start debugging. + +You can run Jest in debug mode using the `test:debug` `package.json` script. The `test:debug` `package.json` script uses the [`--inspect-brk`](https://nodejs.org/api/debugger.html#v8-inspector-integration-for-nodejs) flag, so you should see that debugger will have paused on Jest's first line of execution. From here you can set breakpoints and then use the "Continue (F5)" option to try and encounter your first breakpoint. + +### 2. "Launch & Attach to Jest" + +Select this option if Jest is not currently running and hit the green play button to start debugging. This will start Jest in debug mode. + +[Learn more about debugging with VS Code through its "Debugging" user guide.](https://code.visualstudio.com/docs/editor/debugging) + +## Playwright Tests with Visual Studio Code Extension + +Using VS Code with the [Playwright extension](https://marketplace.visualstudio.com/items?itemName=ms-playwright.playwright) to debug tests is the recommended method for debugging Playwright. The Playwright docs have [a great guide on how to use the extension](https://playwright.dev/docs/getting-started-vscode) that includes [a section specifically on debugging](https://playwright.dev/docs/getting-started-vscode#debugging-tests). + +Note that this method does not work with Electron. For that we recommend the [Playwright Inspector](#playwright-tests-with-playwright-inspector). + +## Playwright Tests with Playwright Inspector + +The Playwright Inspector is a GUI tool that's an alternate method for debugging tests. We recommend debugging with [VS Code's Playwright extension](#playwright-tests-with-visual-studio-code-extension) if possible, but this is the go-to option if you are not coding with VS Code. Also, if your project is Electron-based, this is actually the best option for debugging because Playwright's support for Electron is currently experimental and is incompatible with the extension. + +The Playwright docs have [a great guide on how to debug with the Playwright Inspector](https://playwright.dev/docs/debug#playwright-inspector). + +## webpack Build Process with Google Chrome + +First start webpack in debug mode using a debugging `package.json` build script like `npm run build:debug` or `npm run build:production:debug`. + +Note that if you're using the Docker dev environment, you must run these commands from within the container for them to work. + +You should see something like this appear in your terminal: + +``` +Debugger listening on ws://0.0.0.0:9231/3da93a0a-8478-4d30-89ff-48ea8474604c +For help, see: https://nodejs.org/en/docs/inspector +``` + +Next, open up Google Chrome and navigate to [`chrome://inspect`](chrome://inspect). + +First, we need to make sure that Chrome can find the debugging process. Make sure that "Discover network targets" is checked and then click on the "Configure..." button next to it. In the "Target discovery settings" modal that pops up, add the host and port (in this case it is `localhost:9231`, but may differ for your scenario) and click "Done". + +Now Chrome should have found the webpack debug process under "Remote Target". Click on "inspect" and a new Chrome DevTools window should open up where you'll be able to debug the build process. + +The build debugging `package.json` scripts use the [`--inspect-brk`](https://nodejs.org/api/debugger.html#v8-inspector-integration-for-nodejs) flag, so you should see that DevTools will have paused on webpack's first line of execution. From here you can set breakpoints and then use the "Continue (F5)" option to try and encounter your first breakpoint. + +[Learn more about debugging with Chrome DevTools through its "Debug JavaScript" tutorial.](https://developer.chrome.com/docs/devtools/javascript) diff --git a/docs/developing/docker-environments.md b/docs/developing/docker-environments.md new file mode 100644 index 00000000..6d46ffed --- /dev/null +++ b/docs/developing/docker-environments.md @@ -0,0 +1,343 @@ +# Docker Environments + +LJAS provides two different [Docker](https://docker.com) environments: + +1. **Development Environment** + An alternative to the native dev environment that runs the entire app in a containerized Docker environment. It is available for all projects except for Electron-based ones. +2. **End-to-End Test Environment** + A specialized Docker environment specifically for end-to-end (E2E) testing using [Playwright](https://playwright.dev). It is available for all frontend-related projects. + +## Contents + +- [Docker vs. Native Environments](#docker-vs-native-environments) +- [Setting Up the Docker Dev Environment](#setting-up-the-docker-dev-environment) +- [Setting Up the Docker End-to-End Test Environment](#setting-up-the-docker-end-to-end-test-environment) +- [Docker Basics](#docker-basics) + - [Installing Docker](#installing-docker) + - [Shutting Down a Docker Environment](#shutting-down-a-docker-environment) + - [Getting Container Information](#getting-container-information) + - [Accessing Containers Logs](#accessing-container-logs) + - [Running Terminal Commands Inside the Container](#running-terminal-commands-inside-the-container) +- [More Learning Resources](#more-learning-resources) +- [Connecting to Docker Databases Through a Terminal](#connecting-to-docker-databases-through-a-terminal) +- [Hybrid Native/Docker Development Environment](#hybrid-nativedocker-development-environment) +- [Developing Inside a Container with Visual Studio Code](#developing-inside-a-container-with-visual-studio-code) +- [Performance Tips](#performance-tips) +- [Configuration](#configuration) +- [Troubleshooting](#troubleshooting) + +## Docker vs. Native Environments + +There are a few things you will need to consider when comparing working natively versus working in containers if you're new to container-based dev environments. + +### Docker Benefits + +#### It makes the dev environment perform more consistently. + +You can be more confident that your dev environment will behave the same as your teammates, even if they work on a different operating system, thus reducing the number of occurrences of "it works on my machine." You can still benefit from this when working alone too if you find yourself switching between different machines. + +#### Skip most of the setup process by installing Docker. + +When setting up a project natively, you will need to need to globally install some dependencies like [Node.js](https://nodejs.org) and databases which can conflict with other existing installations of those dependencies on your machine. These conflicts often happen when you work on multiple projects that rely on differing, incompatible versions of the same dependency on the same machine. + +One solution is to upgrade the projects so they all depend on the same version, but that can be a time consuming process that involves resolving a cascading series of dependency compatibility and migration issues. + +Another solution is to get multiple, different versions of a dependency to work simultaneously. Sometimes you'll have to rely on specialized methods or tools accomplish this. For example, for Node.js you would need to install something like [nvm](https://github.com/nvm-sh/nvm), keep track of what version of Node.js is currently running, and switch to other versions when necessary. + +Docker environments avoid this issue entirely by running the exact versions of the dependencies you need in an isolated, containerized environment which cannot conflict with anything natively on your machine. + +Some dependencies have more complicated setup processes as well. Databases are an example of this as they have more involved installation processes and then require additional steps to get working with [Prisma](https://prisma.io). Docker environments significantly streamline this process by handling the entire setup process for you out-of-the-box. You won't need to worry about setting a database username or password, a connection string, etc. as that is all set for you by default. + +### Docker Trade-Offs + +#### You should learn yet another thing: Docker. + +While you can get away with just using `docker compose up`, `docker compose stop`, and `docker compose down` for a while, at some point you will probably need to do something other than these three commands. + +Even though the Docker environments do not require expert-level Docker experience, even acquiring a basic understanding of it still means that you need to spend time learning another technology which can be an issue for some people. + +#### Docker can be resource intensive for some machines. + +Because Docker is limited to a subset of your host machine's resources, everything running within the container will always be slower when compared to running everything natively. Usually this is not very noticeable for higher-end machines, but this can be a significant problem for machines with weaker hardware. + +The good thing about Docker is that it is extremely easy to get the containers running and torn down, so it won't hurt to try spinning up the Docker dev environment just to see how it works for your machine. If you experience less than acceptable performance, take a look at ["Performance Tips" section](#performance-tips) before potentially settling on the native dev environment. + +#### Caveats concerning linting, formatting, and type checking. + +The Docker dev environment uses a [bind mount](https://docs.docker.com/storage/bind-mounts) to give the container direct access to the project directory on your host machine. The only directory that is skipped is the `node_modules` directory as its contents can vary depending on operating system, so the container will generate its own unique one. + +The problem this causes is that if you're natively running terminal commands or editor functionalities, they won't have access to the container's `node_modules` directory which will break functionality around ESLint, Prettier, and type checking while you're coding natively. + +One solution to this is to have another `node_modules` directory specifically for your host machine's operating system, so you will need to run `npm ci` (and `npm run prisma generate` if you're working with a database) natively so your terminal commands and editor functionalities can perform properly. However, this causes another problem because now you have two different `node_modules` directories: one in the host machine and one in the container. Because of this, you will need to make sure that both are always up-to-date, otherwise you may encounter unexpected behavior. + +Most people are okay with having two `node_modules` directories, but if you don't want to worry about that, you can alternatively use VS Code to develop inside the container which we cover in the ["Developing Inside a Container with Visual Studio Code" section](#developing-inside-a-container-with-visual-studio-code). Note that this option's own trade-off is that it means you have to use VS Code and, when the container stops or crashes, the connected VS Code instance will also stop working as well which is inconvenient. + +#### The Docker environments are consistent across different machines until they aren't. + +You may have noticed in the benefits section that we say, "It makes the dev environment perform _more consistently_." We cannot say it performs _100% consistently_ because unfortunately there are always weird cases that come up where even a Docker container will run fine on one machine but run into a problem on another, requiring a machine-specific fix to do. + +It is true that the Docker environments do significantly reduce the "it works on my machine" problems when compared to native environments, but it does not completely eliminate it. Please refer to the ["Troubleshooting" section](#troubleshooting) if you encounter any problems. + +## Setting Up the Docker Dev Environment + +Native dev environments may have many multiple prerequisites, but Docker environments only require Docker. You can learn how to install Docker by reading the ["Installing Docker" section](#installing-docker). + +Once Docker is installed, follow the instructions for getting started with the Docker dev environment in the `README.md` for your project. + +## Setting Up the Docker End-to-End Test Environment + +If you're running a frontend-related project that is not Electron-based, then you will have access to a specialized Docker test environment specialized for end-to-end (E2E) testing with Playwright. + +The Docker E2E test environment is completely separate from the Docker dev environment, so it will have its own unique set of containers, networks, and volumes, allowing it to be run alongside the Docker dev environment without any conflicts. + +This separation is highlighted particularly when working with databases. If the dev and test environments shared the same database, the Playwright tests would generate data that would pollute your dev environment which is not desirable for most people. Conversely, the dev environment could also negatively affect the reliability of Playwright's test results. Keeping things separate makes working with the databases simpler and cleaner, and helps to improve stability and trustworthiness for Playwright. + +Just like the Docker dev environment, you will only need Docker which you can learn how to install by reading the ["Installing Docker" section](#installing-docker). Once that's installed, follow the instructions for getting started with the Docker dev environment in the `README.md` for your project. + +The only difference is in the final step where instead of running `docker compose up` to start the dev environment, run the following command in the project's root directory to start the test environment instead: + +```console +docker compose -f docker-compose.e2e.yml up +``` + +Once the test environment is running, you can [run Playwright](./testing.md#running-playwright-tests) against it as usual. + +To shut down the test environment, you can remove the containers through Docker Desktop or run this command in the project's root directory: + +```console +docker compose -f docker-compose.e2e.yml down +``` + +Note that the Docker E2E test environment produces a production build. This means that rebuilds will be slower when compared to the dev environment, but it allows Playwright tests to be executed in an environment that is more accurate to what end-users will experience, giving more value and reliability to E2E test results. + +Also note that database data is not persisted by default for the Docker E2E test environment so that Playwright can start with a consistent, clean slate to test off of. If you need to persist data, shut down the test environment if it is running, open your project's `docker-compose.e2e.yml` file, and uncomment the necessary database volume-related lines. The database data will be persisted in these volumes the next time you start the test environment. + +## Docker Basics + +This section will go over some basic things for Docker intended for people who want to use the Docker environments without any Docker experience. + +#### Installing Docker + +There are a few different ways to get Docker up and running on your machine, but we suggest installing [Docker Desktop](https://docker.com/products/docker-desktop) which will install Docker and a GUI that lets you manage your containers. + +Even if you intend to completely ignore the GUI and interface with Docker solely through terminal commands, we still recommend Docker Desktop because it simplifies the installation process significantly. + +#### Shutting Down a Docker Environment + +You can shut a Docker environment down with the following options: + +- Press Ctrl+C in the terminal where the container logs are output to stop all containers in the environment. +- Use Docker Desktop to stop/remove the environment's containers. + +Note that stopping a container makes it temporarily inactive so it will no longer consume memory on your native machine, but it will take up disk space. Starting a stopped container is fast and will let your app quickly get back up and running. + +Removing a container deletes the container and everything within it that is not inside the project directory (which is the project directory on your native machine and the `/code` directory in the app container) or a volume. This completely frees up all the disk space the container was taking on your native machine. Starting a Docker environment again means that it will have to create new containers which can potentially be a slow process if the build cache is invalidated. + +Alternatively, you can stop or remove a dev environment's containers by navigating to a project directory and running [`docker compose stop`](https://docs.docker.com/reference/cli/docker/compose/stop) or [`docker compose down`](https://docs.docker.com/reference/cli/docker/compose/down), respectively. + +To shut down a test environment, navigate to the project's root directory and run `docker compose -f docker-compose.e2e.yml down`. + +#### Getting Container Information + +You can run [`docker ps` (shorthand for `docker container ls`)](https://docs.docker.com/reference/cli/docker/container/ls) to see all currently running containers and information on them like container ID, what image they were built from, up-time, ports, etc: + +```console +docker ps +``` + +You can also view stopped containers by using the [`-a` option (shorthand for `--all`)](https://docs.docker.com/reference/cli/docker/container/ls/#all) like so: + +```console +docker ps -a +``` + +Alternatively, you can view this information with Docker Desktop in the "Containers" tab. + +#### Accessing Container Logs + +If you used [`docker compose up`](https://docs.docker.com/reference/cli/docker/compose/up) to start an environment, the terminal you ran the command in will display all of the logs output. + +If you don't want the logs to occupy your terminal, you can start the environment in detached mode by passing the [`-d` option (shorthand for `--detach`)](https://docs.docker.com/engine/reference/run/#foreground-and-background) like so: + +```console +docker compose up -d +``` + +This starts the containers in the background so you can keep using your existing terminal for something else. You can always access the logs later using [`docker logs` (shorthand for `docker container logs`)](https://docs.docker.com/reference/cli/docker/container/logs) like so: + +```console +docker logs CONTAINER_NAME -f +``` + +You can close the logs by pressing Ctrl+C, and even though the logs will have closed, the containers running the environment will continue to work uninterrupted in the background. + +Alternatively, you can view container logs through Docker Desktop by clicking on it in the "Containers" tab and then viewing its "Logs" tab. + +#### Running Terminal Commands Inside the Container + +You can pass commands from your host machine to the container using [`docker exec` (shorthand for `docker container exec`)](https://docs.docker.com/reference/cli/docker/container/exec) commands, but we think it's easier to just gain full access to the container's [Bash](https://gnu.org/software/bash) using this command: + +```console +docker exec -it CONTAINER_NAME bash +``` + +Now the container's Bash will open and any command you run will execute within the context of the container until you close it with Ctrl+C. You will see that the Bash prompt will include a 🐳 emoji to clarify that you are working within the container. + +Alternatively, you can also access the terminal inside the container with Docker Desktop by going to the "Containers" tab, selecting the container you want to access, and clicking on the "Terminal" tab. + +## More Learning Resources + +The following resources are beginner-level guides from the [Docker docs](https://docs.docker.com) that will teach you fundamental Docker concepts that will be useful when using LJAS's Docker environments. + +- [Getting started: Get Docker Desktop](https://docs.docker.com/get-started/get-docker/) +- [The basics: What is a container?](https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-container) +- [The basics: What is an image?](https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-an-image) +- [The basics: What is Docker Compose?](https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-docker-compose) + +## Connecting to Docker Databases Through a Terminal + +After a database container is up and running, you can connect to it through a terminal with the following commands depending on your database type: + +### MongoDB + +```console +docker exec -it MONGO_CONTAINER_NAME mongo -u mongo +``` + +### PostgreSQL + +```console +docker exec -it POSTGRES_CONTAINER_NAME -u postgres psql +``` + +## Hybrid Native/Docker Development Environment + +It is possible to run parts of the project natively and other parts of it with Docker at the same time. We refer to this as a hybrid dev environment. + +We go over how to setup a hybrid dev environment in the ["Connecting a Natively Running App with a Containerized Database" section in the "Database" document](./databases/README.md#connecting-a-natively-running-app-with-a-containerized-database) where we demonstrate how to connect a natively running app to a database running inside a container. + +## Developing Inside a Container with Visual Studio Code + +VS Code allows you to develop inside of containers, so we have preconfigured the Docker dev environment to work with this feature to make things more convenient for those who prefer this method of development. + +Developing inside a container allows you to avoid [one potential drawback with using the Docker dev environment where you need to worry about two different `node_modules` directories](#caveats-concerning-linting-formatting-and-type-checking). An added benefit to this method is that it also sets up all of the recommended VS Code extensions for you and runs the development apps in debug mode so you can have all linting, formatting, type checking, debugging, and terminal features ready out-of-the-box. + +Unfortunately this method does introduce a new drawback which happens when the container stops or crashes: the connected VS Code instance will also stop working and you'll be unable to save your work in progress. The code will still remain in limbo in your editor so it won't be lost, but it is still quite inconvenient. + +Before you develop inside a container, you must have the Docker dev environment setup, so follow the instructions for getting started with it in the `README.md` for your project beforehand. Once that's ready, perform the following steps: + +1. Open VS Code and install the [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension. + +2. Next, run `docker compose up` to start the Docker dev environment. + +3. After all of the containers are running, return to VS Code and [attach to the container](https://code.visualstudio.com/docs/devcontainers/attach-container#_attach-to-a-docker-container) running the app service. So for example, if working off of the [Express + PostgreSQL starter](../../starters/express-postgres), you would select the `ljas-express-postgres` container. + +4. Once the attached VS Code instance is open, open `/code` folder in the explorer and run `cd /code` in the terminal. + +If you would like to read more about this VS Code feature, read the ["Developing inside a Container" document in the VS Code docs](https://code.visualstudio.com/docs/devcontainers/containers). + +## Performance Tips + +If you're running into performance issues, first check that your virtual disk space still has reasonable remaining capacity. If it doesn't, read the solution for the ["I am running into issues with Docker and disk space. How do I deal with that?" question in the "Troubleshooting" section](#i-am-running-into-issues-with-docker-and-disk-space-how-do-i-deal-with-that). + +Next, you may want to consider allocating more of your native hardware's resources to Docker besides disk space. You can configure how many CPUs and how much memory can be used by Docker in the "Resources" tab in the Docker Desktop settings. + +Finally, you can consider using a hybrid dev environment which we talk about in the ["Hybrid Native/Docker Development Environment" section.](#hybrid-nativedocker-development-environment) + +## Configuration + +Read the [Docker configuration document](../configuration/docker.md) to learn how it is configured and how to customize it yourself. + +## Troubleshooting + +This section is for common solutions to some problems you may encounter when dealing with Docker environments. + +### Problems + +- [I am running into issues with Docker and disk space. How do I deal with that?](#i-am-running-into-issues-with-docker-and-disk-space-how-do-i-deal-with-that) +- [I am running into problems preventing me from running Docker environments on Windows.](#i-am-running-into-problems-preventing-me-from-running-docker-environments-on-windows) +- [Docker keeps reusing a stale image when I don't want it to. How do I force Docker to create a completely fresh one?](#docker-keeps-reusing-a-stale-image-when-i-dont-want-it-to-how-do-i-force-docker-to-create-a-completely-fresh-one) +- [Changes to my code are not being seen by nodemon or webpack when they are running in a container.](#changes-to-my-code-are-not-being-seen-by-nodemon-or-webpack-when-they-are-running-in-a-container) +- [Playwright does not work in the Docker dev environment.](#playwright-does-not-work-in-the-docker-dev-environment) + +--- + +#### I am running into issues with Docker and disk space. How do I deal with that? + +Docker's philosophy is to generally keep as many objects, e.g. images, containers, and volumes, as possible until they are explicitly deleted by the user. As a result, the more Docker is used, the more common it is for it to take up a lot of disk space. + +So if Docker is taking up more disk space than you would like, the first thing you should do is delete all dangling objects using a prune command. [`docker image prune`](https://docs.docker.com/reference/cli/docker/image/prune) is probably the first command you should try, but if you still need to free up more disk space after running that, consider using [`docker volume prune`](https://docs.docker.com/reference/cli/docker/volume/prune), [`docker builder prune`](https://docs.docker.com/reference/cli/docker/builder/prune), or [`docker system prune`](https://docs.docker.com/reference/cli/docker/system/prune). You can read more about pruning by reading the ["Prune unused objects" document in the Docker docs](https://docs.docker.com/engine/manage-resources/pruning). + +If you've performed all the pruning you can but still need more space, manually go through all your containers, images, and volumes and delete anything that you can confirm is unnecessary. After that, re-run prune commands and then if you still need more virtual disk space for Docker, you can allocate more by adjusting its limit in the "Resources" tab in the Docker Desktop settings. + +--- + +#### I am running into problems preventing me from running Docker environments on Windows. + +When trying to start containers on Windows, you may encounter an error like: + +``` +failed to solve: rpc error: code = Unknown desc = failed to solve with frontend dockerfile.v0: failed to create LLB definition: failed to authorize: rpc error: code = Unknown desc = failed to fetch anonymous token: unexpected status: 503 Service Unavailable +``` + +You are most likely running Linux containers which are intended for usage on Linux or macOS. When running Docker containers on Windows, it is expected that you use Windows containers. + +To switch to them, right-click the Docker icon in the nofication area of the taskbar, and select "Switch to Windows containers..." To use the command line to switch between containers, run: + +``` +& $Env:ProgramFiles\Docker\Docker\DockerCli.exe -SwitchDaemon +``` + +--- + +#### Docker keeps reusing a stale image when I don't want it to. How do I force Docker to create a completely fresh one? + +After creating an image the first time, sometimes you may encounter cases where Docker won't create a new image when you want it to. If this happens, you can force it to run the image build process using this command: + +```console +docker compose up --build +``` + +If a new image still isn't built even after forcing the image build process to occur, then that means Docker is using the build cache during the entire process. You can force it to avoid using this cache by passing the [`--no-cache` option](https://docs.docker.com/reference/cli/docker/compose/build/#options) to [`docker compose build`](https://docs.docker.com/reference/cli/docker/compose/build) like so: + +```console +docker compose build --no-cache +``` + +This will force Docker to build a completely new image which you can then produce containers from using `docker compose up` afterwards. + +Note that if you run into this issue a lot, you should identify issues in your Docker configuration and make improvements so it can invalidate the build cache on its own. You should avoid manually running these commands regularly and should treat it as a last resort. + +--- + +#### Changes to my code are not being seen by nodemon or webpack when they are running in a container. + +Some machines run into issues with watching files in Docker containers. + +To resolve this issue with nodemon, pass the `--legacy-watch` (or `-L`) flag whenever it is run. It is likely that you will need to update your `dev` `package.json` script with it. For more information on this, refer to the ["Application isn't restarting" in the nodemon README](https://github.com/remy/nodemon?tab=readme-ov-file#application-isnt-restarting). + +To resolve this issue with webpack, set the `watchOptions.poll` option in a webpack configuration file. For more information on this, refer to the ["Watch and WatchOptions" page in the webpack docs](https://webpack.js.org/configuration/watch/#watchoptionspoll). + +--- + +#### Playwright does not work in the Docker dev environment. + +Playwright is not setup by default in the Docker dev environment because we want to encourage you to use the Docker end-to-end (E2E) test environment instead. The test environment runs in a production environment which will more accurately represent the experience your end-users will have, and the dev environment's image building process becomes much faster as it will skip setting up Playwright. + +Still, some may want to run Playwright in the dev environment as iteration there is much faster when compared to iteration in the test environment, so you can get Playwright working in the dev environment by using the `INSTALL_PLAYWRIGHT_DEPS` build argument that, when set to `true`, will perform the Playwright dependency installation step during the image building process. + +There are a couple of ways of setting up build arguments, but one way to do it is to run the following command: + +```console +docker compose build --build-arg INSTALL_PLAYWRIGHT_DEPS=true +``` + +After the image is built, subsequent runs of `docker compose up` will skip the image building process and jump straight to building a new container that will have Playwright setup within it. + +If you end up wanting to get rid of Playwright, you can rerun the build process without any build arguments like so: + +``` +docker compose build +``` + +This is basically the same thing as setting `INSTALL_PLAYWRIGHT_DEPS` to `false`, but it's unnecessary to explicitly do that since the `Dockerfile` will do it for you by default. diff --git a/docs/developing/javascript-typescript.md b/docs/developing/javascript-typescript.md new file mode 100644 index 00000000..f8b553aa --- /dev/null +++ b/docs/developing/javascript-typescript.md @@ -0,0 +1,117 @@ +# JavaScript & TypeScript + +## Contents + +- [ECMAScript Version](#ecmascript-version) +- [TypeScript Version](#typescript-version) +- [Creating JavaScript, TypeScript, and JSX-Related Files](#creating-javascript-typescript-and-jsx-related-files) +- [Linting](#linting) +- [Type Checking](#type-checking) +- [Formatting](#formatting) +- [Auto & Hot Reloading](#auto--hot-reloading) +- [Configuration](#configuration) + +## ECMAScript Version + +LJAS allows you to use most of the latest ECMAScript features thanks to [Babel](https://babeljs.io/docs). You can view what features are available in [Babel's docs for `@babel/preset-env`](https://babeljs.io/docs/babel-preset-env). + +## TypeScript Version + +LJAS currently uses version ~5.3.3. Most of the time we are slightly behind the latest version because we only upgrade to the newest version that [`@typescript-eslint`](https://typescript-eslint.io) supports. + +## Creating JavaScript, TypeScript, and JSX-Related Files + +All of the application's ECMAScript-related files must exist in the `src/` directory. + +If you are using a JavaScript-only starter, these files will commonly have a `.js` file extension. + +If you are using a TypeScript starter, you will usually be using files with a `.ts` file extension instead, but JavaScript code under `.js` files is still allowed although it is not recommended. + +If your ECMAScript code uses [JSX](https://react.dev/learn/writing-markup-with-jsx), then you will need to add an "x" to the end of the file extension. So for JavaScript that would be `.jsx` and for TypeScript that would be `.tsx`. + +We understand it may not be common to require `.jsx` file extensions for code involving JSX, but we thought it made sense to be consistent with [TypeScript's rule that restricts JSX to files with `.tsx` file extensions](https://typescriptlang.org/docs/handbook/jsx.html). If you want to alter that behavior you can go into the ESLint config file, `.eslintrc.js`, and change the [`react/jsx-filename-extension` rule](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md). + +## Linting + +LJAS uses [ESLint](https://eslint.org) to lint JavaScript and TypeScript. You can run it with the following `package.json` script: + +```console +npm run lint +``` + +ESLint has a [`--fix` option](https://eslint.org/docs/latest/use/command-line-interface#--fix) which will cause it to automatically fix as many problems as possible. A shortcut for passing this option is available as the following script: + +```console +npm run lint:fix +``` + +Instead of using `package.json` scripts, we suggest enabling ESLint in your code editor to lint in real-time. We show how to set this up with [Visual Studio Code (VS Code)](https://code.visualstudio.com) in the ["Install Extensions" section in the "Code Editors" document](../setup/code-editors.md#install-extensions). + +To learn how to configure ESLint, read the [ESLint configuration document](../configuration/eslint.md). + +## Type Checking + +You can run the TypeScript compiler to type check the project source code by running the following `package.json` script: + +```console +npm run check-types +``` + +Instead of using this script, we suggest enabling real-time type checking in your code editor. We suggest using VS Code since it does this for you out-of-the-box. + +Starting from v1.x.x, LJAS has dropped support of Flow, but we have the [todo list example](../../examples/todo-list) ported from v0.1.1 which still uses it. Please note that this example is considered legacy so it will not receive significant future updates. + +## Formatting + +LJAS uses [Prettier](https://prettier.io) to format all code. To identify all files with code style issues, run the following `package.json` script: + +```console +npm run format +``` + +Note that this is an alias for `npm run format:check` which only identifies issues and does not make any changes to files. + +If you want to automatically address all of these code style issues, use the following script: + +```console +npm run format:write +``` + +Instead of using these scripts, we suggest enabling formatting on save with Prettier in your code editor. We show how to set this up with VS Code in the ["Install Extensions" section in the "Code Editors" document](../setup/code-editors.md#install-extensions). + +To learn how to configure Prettier, read the [Prettier configuration document](../configuration/prettier.md). + +## Auto & Hot Reloading + +We utilize [webpack](https://webpack.js.org)'s [watch mode](https://webpack.js.org/configuration/watch) for [Node.js](https://nodejs.org)-based source code and [webpack-dev-server](https://webpack.js.org/configuration/dev-server) for browser-based source code to watch the `src/` directory and create new builds if any changes occur there. This is done during `package.json` scripts like `build:watch` and `dev` (e.g., `npm run backend:build:watch`, `npm run frontend:dev`, `npm run main:build:watch`, `npm run renderer:dev`). + +Note that webpack alone only generates a new build and will not restart the app process. This means that, for most build processes except for those involving hot reloading, changes may not be reflected in a running app until you shut down its current one and start a completely new app process. To prevent you from having to manually do that, [nodemon](https://nodemon.io) watches webpack for you, waiting for it to generate a new build so it can restart the app at the correct time, enabling auto reload functionality. + +So one, not recommended, way to get auto reloading working is to run a command similar to the following: + +``` +npm run build:watch && npm run start:debug +``` + +In this case, `npm run build:watch` runs webpack which will create new builds when changes occur to the source code. Then `npm run start:debug` runs nodemon which will run the app process and then restart it after webpack finishes a new build. + +The recommend method is to use the `dev` `package.json` script that essentially does all of this for you except in [a better way with concurrently](https://github.com/open-cli-tools/concurrently): + +``` +npm run dev +``` + +Frontend React-based build processes do not rely on auto reloading and nodemon in the same way because [React Fast Refresh](https://reactnative.dev/docs/fast-refresh) is used to show your app's changes instead. This feature is setup with [React Refresh Webpack Plugin](https://github.com/pmmmwh/react-refresh-webpack-plugin) and activates hot reloading which enables webpack-dev-server to seamlessly update specific modules and components while the app is running, only falling back to a full reload when absolutely necessary. + +This allows React development to iterate faster because changes will be "live patched" to the app process which will run continuously and uninterrupted. This is in contrast to auto reloading where nodemon has to completely restart the app process every time a change occurs. + +## Configuration + +Read the following configuration documents to learn how the corresponding configurations work and how to customize them yourself: + +- [Babel](../configuration/babel.md) +- [ESLint](../configuration/eslint.md) +- [nodemon](../configuration/nodemon.md) +- [Prettier](../configuration/prettier.md) +- [TypeScript](../configuration/typescript.md) +- [webpack](../configuration/webpack.md) diff --git a/docs/developing/package-management.md b/docs/developing/package-management.md new file mode 100644 index 00000000..05d6cad5 --- /dev/null +++ b/docs/developing/package-management.md @@ -0,0 +1,128 @@ +# Package Management + +Like most JavaScript projects, LJAS relies on [`package.json`](https://docs.npmjs.com/cli/v10/configuring-npm/package-json) which is a JSON configuration file found your project's root directory. It determines all of the meta information and dependencies for your project. + +## Contents + +- [Package Manager](#package-manager) +- [`package.json` Basics](#packagejson-basics) + - [Package Version Practices](#package-version-practices) + - [Managing Dependencies](#managing-dependencies) + - [Scripts](#scripts) +- [`dependencies` vs. `devDependencies`](#dependencies-vs-devdependencies) +- [Troubleshooting](#troubleshooting) + +## Package Manager + +While there are multiple package managers that support `package.json`, we currently only support [npm](https://npmjs.com) out-of-the-box since it is usually installed alongside [Node.js](https://nodejs.org). Because of this, the docs are written in the perspective of an npm user. + +While LJAS has dropped support of [Yarn](https://yarnpkg.com) starting from v1.x.x, we still have the [todo list example](../../examples/todo-list) ported from v0.1.1 which uses Yarn. Please note that this example is considered legacy so it will not receive significant future updates. + +Switching to a different package manager shouldn't be difficult as long as you do it early, so we highly recommend that you decide on one package manager when you start a new project and stick with it to avoid issues that can arise when switching package managers later in development. + +## `package.json` Basics + +### Package Version Practices + +All version numbers (i.e. your package version or package dependency versions) are supposed to follow [semantic versioning (SemVer)](https://semver.org). Sometimes you may encounter a package that doesn't respect it which is unfortunate. Avoid being a headache for the community and please follow SemVer practices correctly! + +### Managing Dependencies + +Install new packages with the [`npm install` command](https://docs.npmjs.com/cli/v6/commands/npm-install) like so: + +```console +npm install react +``` + +This command also lets you do other things. For example, you can specify which version of a package to install like so: + +```console +npm install react@17.0.2 +``` + +You can also install multiple packages by passing in multiple arguments like so: + +```console +npm install react react-dom +``` + +When you install a package, it will add itself under the [`dependencies` field](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#dependencies) by default, but you can add a package to different dependency category too. For example, if you want to add a development dependency, you can use a command like this: + +```console +npm install jest --save-dev +``` + +This will install Jest and add it under the [`devDependencies` field](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#devdependencies). A shorter alternative to the `--save-dev` flag is `-D`. + +If you need to update the version for existing dependency, you can use the [`npm update` command](https://docs.npmjs.com/cli/v10/commands/npm-update) like so: + +```console +npm update react@18.3.1 +``` + +Uninstalling existing dependencies is done with the [`npm uninstall` command](https://docs.npmjs.com/cli/v6/commands/npm-uninstall) like so: + +```console +npm uninstall react +``` + +When you need to install all dependencies during setup for a project, run the [`npm ci`](https://docs.npmjs.com/cli/v10/commands/npm-ci) command to do so: + +```console +npm ci +``` + +This command acts similarly to running [`npm install` without passing in any arguments](https://docs.npmjs.com/cli/v10/commands/npm-install#description) except it will not perform any changes to [`package-lock.json`](https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json). + +### Scripts + +The [`scripts` field](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#scripts) allows you to define `package.json` scripts which become terminal commands. We provide many scripts for you to use out-of-the-box which we cover in [other documents in the "Developing" section of the docs](../developing). + +Here is an example of our lint script which will run ESLint and identify potential problems in your code: + +```console +npm run lint +``` + +It is a good idea to add scripts for commonly used and inconveniently long terminal commands to this field. + +## `dependencies` vs. `devDependencies` + +LJAS organizes all packages that are required to execute the build process and application in the `dependencies` field like React and webpack. All other packages that aren't critical to the build process and application are placed under the `devDependencies` field. So for example, while ESLint and Jest are vital for development, they are not used by the application when it runs or the build process, so they would fall into this latter category. + +## Troubleshooting + +### Problems + +- [Some of my packages are having problems running.](#some-of-my-packages-are-having-problems-running) +- [How do I figure out which packages are dependent on a specific package?](#how-do-i-figure-out-which-packages-are-dependent-on-a-specific-package) + +--- + +#### Some of my packages are having problems running. + +When in doubt, first try deleting your existing `node_modules` directory. This can be done by running the following command in your project's root directory: + +```console +rm -rf node_modules +``` + +Then reinstall all of your project's dependencies. + +Alternatively, you can remove the existing `node_modules` directory and create a brand new one using a single command called [`npm ci`](https://docs.npmjs.com/cli/v10/commands/npm-ci): + +```console +npm ci +``` + +--- + +#### How do I figure out which packages are dependent on a specific package? + +Sometimes you need to figure out which packages are dependent on a specific package. This can be handy in situations where you need to resolve version conflicts. Sometimes looking at your `package.json` alone isn't enough as there could be deeper, unseen relations in your project's dependency tree that are causing problems. + +A good way to figure this out is to use the [`npm ls` command](https://docs.npmjs.com/cli/v6/commands/npm-ls) which allows you to visualize your project's dependency tree. For example, you can see which packages depend on React using the following command: + +```console +npm ls react +``` diff --git a/docs/developing/react-ssr.md b/docs/developing/react-ssr.md new file mode 100644 index 00000000..c91ee337 --- /dev/null +++ b/docs/developing/react-ssr.md @@ -0,0 +1,47 @@ +# React Server-Side Rendering + +This document explains the details behind the approach LJAS uses to support React server-side rendering (SSR) since there are a few different ways it could be setup. + +This document is only relevant to the following SSR-based starter projects: + +| Starter Project Name | JavaScript | TypeScript | +| ------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| React + Express + MongoDB with SSR | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-mongo-ssr) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-mongo-ssr-ts) | +| React + Express + PostgreSQL with SSR | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-postgres-ssr) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-postgres-ssr-ts) | + +## Contents + +- [Overview](#overview) +- [Examples](#examples) + +## Overview + +### Separate Frontend & Backend Build Processes + +There are two different webpack build processes, one for the frontend and one for the backend, and they are executed one-after-another in that order because the backend is dependent on the output of the frontend build process. + +It is possible to run the backend without completing the frontend build process, but the whole reason why they are run in sequence is because the frontend build process generates the files that Express needs to render views like the JavaScript, EJS template files, images, etc. So if you run the backend build process alone, you will not be able to develop or use anything that involves a view which might not be a problem if you're working on a team exclusively as a backend API developer or something like that. + +### Handling React on the Backend + +webpack is configured to handle imports and compile all React-related code within the backend, so you are able to import the frontend's components and render views with them using [React DOM's server APIs](https://react.dev/reference/react-dom/server) like [`renderToString`](https://react.dev/reference/react-dom/server/renderToString). + +When a user loads the app in their browser, the backend serves its rendering of the React code, and the browser will execute the JavaScript that runs [`hydrateRoot`](https://react.dev/reference/react-dom/client/hydrateRoot) to have the client-side React attach to the server rendering and take over. + +Also, if you want to, this setup allows you to completely avoid the single-page application (SPA) paradigm where the frontend communicates with the backend through fetch requests. You can give all responsibility of frontend rendering to the backend by using [`renderToStaticMarkup`](https://react.dev/reference/react-dom/server/renderToStaticMarkup). This eliminates the JavaScript requirement for your app which could be very beneficial depending on the use case, although it will mean that a complete page reload will occur when users perform any page navigation. + +### Developing the Frontend + +When you are developing the frontend, there are actually running two servers running at the same time: the Express server and [webpack-dev-server](https://webpack.js.org/configuration/dev-server). + +The Express server is where all of your backend development happens, and while it is possible to develop the frontend with the Express server alone, you will need to reload the web page in the browser every time you change the code which can be cumbersome for UI development. + +webpack-dev-server addresses this by running a separate instance of the frontend that essentially acts like the typical SPA that most React developers are familiar with. This second development server allows us to leverage [React Fast Refresh](https://github.com/pmmmwh/react-refresh-webpack-plugin#readme) and avoid full page reloads when possible. + +The main thing to note about developing with webpack-dev-server is that the frontend will be communicating with the Express server exclusively through fetch requests, so server-side rendering will not occur. It is important to be wary of this and make sure that you check that server-side rendering is still behaving correctly as you develop with webpack-dev-server by testing the frontend through the Express server periodically. + +This means that loading the frontend through the Express server will more accurately replicate behavior in production because server-side rendering will occur. So be mindful of the fact that webpack-dev-server does deviate the true frontend behavior slightly, but understand that we take accept this trade-off so UI development can remain as streamlined as possible. + +## Examples + +- [\*chan](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/examples/starchan): Express server that server-side renders a React frontend diff --git a/docs/developing/styling.md b/docs/developing/styling.md new file mode 100644 index 00000000..05e94723 --- /dev/null +++ b/docs/developing/styling.md @@ -0,0 +1,80 @@ +# Styling + +LJAS supports [CSS](https://w3.org/Style/CSS/Overview.en.html) for all frontend-related projects: + +| Starter Project Name | JavaScript | TypeScript | +| ------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| Basic Browser | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-browser) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-browser-ts) | +| Basic Electron | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-electron) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-electron-ts) | +| React + Browser | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-browser) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-browser-ts) | +| React + Electron | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-electron) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-electron-ts) | +| React + Express + MongoDB with SSR | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-mongo-ssr) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-mongo-ssr-ts) | +| React + Express + PostgreSQL with SSR | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-postgres-ssr) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-postgres-ssr-ts) | + +## Contents + +- [Getting Started](#getting-started) +- [Linting](#linting) +- [Formatting](#formatting) +- [Adding Support for Sass](#adding-support-for-sass) +- [Examples](#examples) + +## Getting Started + +You can create a `.css` anywhere in the `src/` directory and import it in any ECMAScript file. So for example you could create `src/index.css` and then import it in `src/index.js` like so: + +```javascript +import './index.css' +``` + +Then webpack will handle how the CSS gets loaded in the bundle during the build process. + +You can see an example of this in the [`buildCss` `ljas-webpack` example](../../ljas-webpack/examples/buildCss). + +## Linting + +LJAS uses [Stylelint](https://stylelint.io) to lint all CSS-related code. You can run it with the following `package.json` script: + +```console +npm run lint:styles +``` + +Stylelint has a [`--fix` option](https://stylelint.io/user-guide/options/#fix) which will cause it to automatically fix as many problems as possible. A shortcut for passing this option is available as the following script: + +```console +npm run lint:styles:fix +``` + +Instead of using `package.json` scripts, we suggest enabling Stylelint in your code editor to lint in real-time. We show how to set this up with [Visual Studio Code (VS Code)](https://code.visualstudio.com) in the ["Install Extensions" section in the "Code Editors" document](../setup/code-editors.md#install-extensions). + +To learn how to configure Stylelint, read the [Stylelint configuration document](../configuration/stylelint.md). + +## Formatting + +LJAS uses [Prettier](https://prettier.io) to format all code. To identify all files with code style issues, run the following `package.json` script: + +```console +npm run format +``` + +Note that this is an alias for `npm run format:check` which only identifies issues and does not make any changes to files. + +If you want to automatically address all of these code style issues, use the following script: + +```console +npm run format:write +``` + +Instead of using these scripts, we suggest enabling formatting on save with Prettier in your code editor. We show how to set this up with VS Code in the ["Install Extensions" section in the "Code Editors" document](../setup/code-editors.md#install-extensions). + +To learn how to configure Prettier, read the [Prettier configuration document](../configuration/prettier.md). + +## Adding Support for Sass + +To learn how to add support for Sass in your project, refer to the ["Adding Support for Sass" section in the Stylelint configuration document](../configuration/stylelint.md#adding-support-for-sass). + +## Examples + +- [\*chan](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/examples/starchan): Express server that server-side renders a React frontend +- [Asset Test](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/examples/asset-test): Test for LJAS's asset loading capabilities +- [Markdown Editor](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/examples/markdown-editor): Markdown editor desktop app diff --git a/docs/developing/testing.md b/docs/developing/testing.md new file mode 100644 index 00000000..1ecaa4df --- /dev/null +++ b/docs/developing/testing.md @@ -0,0 +1,163 @@ +# Testing + +## Contents + +- [Jest](#jest) + - [Creating Jest Test Files](#creating-jest-test-files) + - [Running Jest Tests](#running-jest-tests) + - [Coverage with Jest](#coverage-with-jest) + - [Debugging Jest Tests](#debugging-jest-tests) + - [Configuring Jest](#configuring-jest) + - [Jest Learning Resources](#jest-learning-resources) +- [Playwright](#playwright) + - [Creating Playwright Test Files](#creating-playwright-test-files) + - [Running Playwright Tests](#running-playwright-tests) + - [Debugging Playwright Tests](#debugging-playwright-tests) + - [Configuring Playwright](#configuring-playwright) + - [Playwright Learning Resources](#playwright-learning-resources) + +## Jest + +[Jest](https://jestjs.io) is setup for all projects. + +### Creating Jest Test Files + +LJAS uses the default Jest behavior which only has two patterns that you will need to follow if you want Jest to be able to find your tests without changing the [`testMatch` option](https://jestjs.io/docs/configuration#testmatch-arraystring) in the Jest config file. + +The first one is that it will match all JavaScript and TypeScript files with `.spec` or `.test` before its file extension. For example, the following file names would be matched: + +- `foo.test.js` +- `bar.spec.jsx` +- `baz.test.ts` +- `xyzzy.spec.tsx` + +The second one is that it will match all JavaScript and TypeScript files within a `__tests__` directory, even if its file name does not have `.spec` or `.test` before its file extension. For example, the following files would be matched: + +- `__tests__/foo.js` +- `bar/__tests__/baz.jsx` +- `__tests__/xyzzy.test.ts` +- `foo/bar/__tests__/plugh.spec.tsx` + +### Running Jest Tests + +Run the `test` `package.json` script to run Jest: + +```console +npm test +``` + +You can also use its shorthand version: `npm t`. + +`npm test` is just an alias for the `jest` command, so you can also pass in any of its [CLI options](https://jestjs.io/docs/cli) like so: + +```console +npm test src -- -t snapshot +``` + +You can also run Jest in [watch mode](https://jestjs.io/docs/cli#--watch) with the `test:watch` `package.json` script: + +```console +npm run test:watch +``` + +### Coverage with Jest + +Run the `test:coverage` `package.json` script to have Jest generate coverage with [Istanbul](https://istanbul.js.org): + +```console +npm run test:coverage +``` + +This will output an HTML coverage report in the `coverage/` directory. You can open this with the following command: + +```console +npm run test:coverage:open +``` + +### Debugging Jest Tests + +To learn how to debug Jest Tests, refer to the ["Jest tests with Visual Studio Code" section in the "Debugging" document](./debugging.md#jest-tests-with-visual-studio-code). + +### Configuring Jest + +Read the [Jest configuration document](../configuration/jest.md) to learn how it is configured and how to customize it yourself. + +### Jest Learning Resources + +- [Jest Docs: Getting Started](https://jestjs.io/docs/getting-started) + Learn the basics of writing and running Jest tests. +- [React Testing Library (RTL) Tutorial](https://robinwieruch.de/react-testing-library) + Learn [RTL](https://testing-library.com/docs/react-testing-library/intro) in a tutorial written by Robin Wieruch. This tutorial is recommended by the [Testing Library docs](https://testing-library.com/docs/react-testing-library/intro#tutorials). +- [Mock Service Worker (MSW) Docs: Getting started](https://mswjs.io/docs/getting-started) + Learn how to use MSW by following their getting started document. + +## Playwright + +[Playwright](https://playwright.dev) is only setup for frontend-related projects: + +| Starter Project Name | JavaScript | TypeScript | +| ------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| Basic Browser | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-browser) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-browser-ts) | +| Basic Electron | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-electron) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/basic-electron-ts) | +| React + Browser | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-browser) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-browser-ts) | +| React + Electron | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-electron) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-electron-ts) | +| React + Express + MongoDB with SSR | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-mongo-ssr) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-mongo-ssr-ts) | +| React + Express + PostgreSQL with SSR | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-postgres-ssr) | [View Source](https://github.com/mattlean/lean-js-app-starter/tree/v1.0.0/starters/react-express-postgres-ssr-ts) | + +### Creating Playwright Test Files + +Playwright will look for all JavaScript and TypeScript files including `.spec` or `.test` before its file extension in the `src/playwright/` directory. For example, the following files would be matched: + +- `src/playwright/foo.test.js` +- `src/playwright/bar.spec.ts` +- `src/playwright/baz/xyzzy.spec.jsx` +- `src/playwright/foo/bar/plugh.spec.tsx` + +### Running Playwright Tests + +Run the `test:e2e` `package.json` script to run Playwright: + +```console +npm run test:e2e +``` + +`npm run test:e2e` is just an alias for the `playwright test` command, so you can also pass in any of its [CLI options](https://playwright.dev/docs/test-cli) like so: + +```console +npm run test:e2e src/playwright -- --project=chromium +``` + +You can also run Playwright in [UI mode](https://playwright.dev/docs/test-ui-mode) with the `test:e2e:dev` `package.json` script: + +```console +npm run test:e2e:dev +``` + +If a test fails, Playwright will serve an HTML report of the results at [`http://localhost:9323`](http://localhost:9323). If you ever want to access this after it has closed, you can use the `test:e2e:report` `package.json` script to serve it again: + +```console +npm run test:e2e:report +``` + +Some prefer running a separate dev server specifically for E2E tests, so we offer a `loadApp` function in `src/playwright/util.js` (or `util.ts` if your project is TypeScript-based) that allows your Playwright tests to switch between the regular dev server host (which by default is http://localhost:8080 or http://localhost:3000 depending on the situation) or the E2E dev server host (which by default is http://localhost:8180 or http://localhost:3100 depending on the situation). + +To switch to the E2E dev server host, set the `E2E` environment variable in the `.env` file to `true`. Then the next time you run Playwright tests through a `test:e2e` script, it will run tests against the E2E dev server host. If you want to switch back to testing against the regular dev server host, set `.env` to `false` or an empty value. + +### Debugging Playwright Tests + +Please refer to the ["Playwright Tests with Visual Studio Code" section](./debugging.md#playwright-tests-with-visual-studio-code) or the ["Playwright Tests with Playwright Inspector" section](./debugging.md#playwright-tests-with-playwright-inspector) in the "Debugging" document. + +### Docker End-to-End Test Environment + +If you're working off of a project that supports Playwright and does not utilize Electron, you will have access to a Docker test environment specialized for working with Playwright tests. + +To learn how to use it, read the ["Setting Up the Docker End-to-End Test Environment" section in the "Docker Environments" document](../developing/docker-environments.md#setting-up-the-docker-end-to-end-test-environment). + +### Configuring Playwright + +Read the [Playwright configuration document](../configuration/playwright.md) to learn how it is configured and how to customize it yourself. + +### Playwright Learning Resources + +- [Playwright Docs: Getting Started](https://playwright.dev/docs/intro) + Learn how to use and write tests with Playwright by following their getting started document. diff --git a/docs/envs/README.md b/docs/envs/README.md deleted file mode 100644 index 68a19305..00000000 --- a/docs/envs/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Environments -* [Web Browser](browser/README.md) -* [Node.js](nodejs/README.md) -* [Desktop](desktop/README.md) \ No newline at end of file diff --git a/docs/envs/browser/README.md b/docs/envs/browser/README.md deleted file mode 100644 index b710cc86..00000000 --- a/docs/envs/browser/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Web Browser -* [Getting Started](getting_started.md) -* [Developing](developing.md) -* [Building](building.md) -* [Dependencies](dependencies.md) -* [Configuration](configuration.md) -* [Examples](examples.md) \ No newline at end of file diff --git a/docs/envs/browser/building.md b/docs/envs/browser/building.md deleted file mode 100644 index a91596a5..00000000 --- a/docs/envs/browser/building.md +++ /dev/null @@ -1,16 +0,0 @@ -# Web Browser: Building -## Production -Use the `build` [`package.json`](../../../package.json) script to create a build for the production environment with webpack. This will involve everything you need to ensure your app works for all targeted browsers while having an optimized build size. To preview the build, use the `start` [`package.json`](../../../package.json) script to host it at [localhost:9090](http://localhost:9090). - -The `build:debug` [`package.json`](../../../package.json) script can be used to debug the webpack configuration with a [Node.js inspector client](https://nodejs.org/en/docs/guides/debugging-getting-started/#inspector-clients). The `build:stats` [`package.json`](../../../package.json) script generates a `stats.production.json` file in the project root directory which can be used with many analysis tools such as [analyse](https://github.com/webpack/analyse). - -The production build process generates `records.json` which is used to store module IDs across separate builds. This allows the generation of longer lasting filenames, makes sure that code split parts gain correct caching behavior, and that modules aren't reordered or moved to another chunk during the bundling process which results to less cache invalidations. **This file should checked into version control.** - -For more details on what the webpack build process is doing, read the ["Configuration: webpack" documentation](configuration.md#webpack). - -## Development -Use the `build:dev` [`package.json`](../../../package.json) script to create a build for the development environment with webpack. The build process will prioritize options that will shortern build times and make development more convenient. To run the build, use the `start:dev` [`package.json`](../../../package.json) script. Although you can use this for development, it is highly recommended you avoid these two scripts and regularly use the `start:dev:watch` [`package.json`](../../../package.json) script instead to utilize auto-reloading and hot loading. Both `start:dev` scripts will host the build at [localhost:8080](http://localhost:8080). - -The `build:dev:debug` [`package.json`](../../../package.json) script can be used to debug the webpack configuration with a [Node.js inspector client](https://nodejs.org/en/docs/guides/debugging-getting-started/#inspector-clients). The `build:dev:stats` [`package.json`](../../../package.json) script generates a `stats.development.json` file in the project root directory which can be used with many analysis tools such as [analyse](https://github.com/webpack/analyse). - -For more details on what the webpack build process is doing, read the ["Configuration: webpack" documentation](configuration.md#webpack). \ No newline at end of file diff --git a/docs/envs/browser/configuration.md b/docs/envs/browser/configuration.md deleted file mode 100644 index fcfbde13..00000000 --- a/docs/envs/browser/configuration.md +++ /dev/null @@ -1,373 +0,0 @@ -# Web Browser: Configuration -## Babel -[Babel](https://babeljs.io) allows you to use newer JavaScript features that are currently not supported by browsers. The config file can be found in the project's root directory as [`.babelrc`](../../../.babelrc). For more info on configurating Babel, read the [Babel "Configure Babel" docs](https://babeljs.io/docs/en/configuration). - -### Plugins -* [@babel/plugin-proposal-class-properties](https://babeljs.io/docs/en/next/babel-plugin-proposal-class-properties.html) - Enable class properties. -* [react-hot-loader/babel](https://github.com/gaearon/react-hot-loader) - Enable support for React Hot Loader. - -### Presets -* [@babel/preset-env](https://babeljs.io/docs/en/babel-preset-env) - A smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms (and optionally, browser polyfills) are needed by your target environments. Target environments are determined by the project's Browserslist. - - The `modules` option is set to `false` because by default we want webpack to handle the ES2015 modules instead of Babel so it can perform optimizations like [tree shaking](https://webpack.js.org/guides/tree-shaking). When running in a test environment, the option is set back to its default value (`"auto"`) so Babel can convert the ES2015 modules to a format Jest can understand. -* [@babel/preset-flow](https://babeljs.io/docs/en/babel-preset-flow) - Enable support for Flow. -* [@babel/preset-react](https://babeljs.io/docs/en/babel-preset-react) - Enable support for React and JSX. When running in a development environment, the `development` option is set to `true` and enables useful developer features like [component stack traces](https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html#component-stack-traces). - -## Browserslist -[Browserslist](https://github.com/browserslist/browserslist) allows you to define browser versions the project should target. The config file can be found in the project's root directory as [`.browserslist`](../../../.browerslist). For more info on configuring Browserslist, read the [Browserslist README](https://github.com/browserslist/browserslist/blob/master/README.md). - -@babel/preset-env uses this config to determine the minimum transforms and polyfills necessary for the build's JavaScript. [Autoprefixer](https://github.com/postcss/autoprefixer) also uses this to determine the minimum vendor prefixes necessary for the build's CSS. - -By default [`.browserslist`](../../../.browerslist) is set to `defaults` which is the equivalent to `> 0.5%, last 2 versions, Firefox ESR, not dead`. It is highly recommended that you change this based on the browsers your users are using. If you use [Google Analytics](https://marketingplatform.google.com/about/analytics), you can generate usage stats from it and determine your config with [browserslist-ga](https://github.com/browserslist/browserslist-ga). - -## ESLint -[ESLint](https://eslint.org) helps identify potential problems and deviations from code style guidelines in your JavaScript. The config file can be found in the project's root directory as [`.eslintrc`](../../../.eslintrc.json). The ignored file configuration can also be found in the root directory as [`.eslintignore`](../../../.eslintignore). For more info on configuring ESLint, read the [ESLint "Configuring ESLint" docs](https://eslint.org/docs/user-guide/configuring). - -### Environments -* Browser: Supports browser global variables -* ES6 (ECMAScript 2015): Supports all ECMAScript 2015 features except for modules -* Node.js: Support Node.js global variables and Node.js scoping - -### Config Extensions -* [`eslint:recommended`](https://eslint.org/docs/rules) - Enables recommended rules for general JavaScript as defined by ESLint. -* [`plugin:flowtype/recommended`](https://github.com/gajus/eslint-plugin-flowtype/blob/master/src/configs/recommended.json) - Enables recommended rules for Flow as defined by eslint-plugin-flowtype. Also sets [babel-eslint](https://github.com/babel/babel-eslint) as the parser since the default parser ([Espree](https://github.com/eslint/espree)) does not support Flow. -* [`plugin:jest/recommended`](https://github.com/jest-community/eslint-plugin-jest#rules) - Enables recommended rules for Jest as defined by eslint-plugin-jest. -* [`plugin:react/recommended`](https://github.com/yannickcr/eslint-plugin-react#recommended) - Enables recommended rules for React as defined by eslint-plugin-react. - -### Parser Options -JSX and ES2015 module support is enabled. - -### Plugins -* [eslint-plugin-flowtype](https://github.com/gajus/eslint-plugin-flowtype) - Enables linting rules for Flow and allows us to use the `plugin:flowtype/recommended` config extension. -* [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) - Enables linting rules for Jest and allows us to use the `plugin:jest/recommended` config extension. -* [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) - Enables linting rules for React and allows us to use the `plugin:react/recommended` config extension. - -### Rules -These specific rules override any rules set by config extensions and will trigger an error if broken. -* 2 space characters for each indentation - * `switch` statements use 1 additional indentation -* Line endings must be Unix -* Strings use single quotes instead of double quotes -* No semicolons - -### Settings -The React and Flow versions match the versions used in the project, as specified by [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react). These versions can be found in [`package.json`](../../../package.json). - -### Ignored Files -[`jest.config.js`](../../../jest.config.js) is ignored as linting the Jest configuration is not necessary. - -## Flow -[Flow](https://flow.org) is a static type checker for JavaScript. The config file can be found in the project's root directory as [`.flowconfig`](../../../.flowconfig). For more info on configuring Flow, read the [Flow ".flowconfig" docs](https://flow.org/en/docs/config). - -### Ignored Files -All stats files generated by a build stats [`package.json`](../../../package.json) script. - -### Options -Flow will look for files with the following extensions: -* css -* js -* json -* jsx -* mjs -* scss - -Also these two lines are included so Flow will not error when styles are imported: -``` -module.name_mapper.extension='css' -> 'empty/object' -module.name_mapper.extension='scss' -> 'empty/object' -``` - -## Jest -[Jest](https://jestjs.io) lets you build and run tests on your JavaScript. The config file can be found in the project's root directory as [`jest.config.js`](../../../jest.config.js). For more info on configuring Jest, read the [Jest "Configuring Jest" docs](https://jestjs.io/docs/en/configuration.html). - -### Options -`moduleNameMapper` is set to the following so snapshots can handle assets like images and fonts as well as styles in spapshot tests: -```javascript -moduleNameMapper: { - "\\.(eot|gif|jpg|jpeg|png|ttf|woff|woff2)$": "/src/__mocks__/fileMock.js", - "\\.(css|scss)$": "/src/__mocks__/styleMock.js" -}, -``` - -`snapshotSerializer` is set to [enzyme-to-json](https://github.com/adriantoine/enzyme-to-json) so Enzyme wrappers are converted to a format compatible with Jest snapshot tests. - -`testPathIgnorePatterns` will have Jest ignore the `node_modules/` (which is ignored by default) and `build/` directories. - -## nodemon -[nodemon](https://nodemon.io) reruns Node.js applications when file changes are detected. For this project it is used to rerun package.json scripts to rebuild and rerun the application. The config file can be found in the project's root directory as [`nodemon.json`](../../../nodemon.json). This file sets what nodemon will watch and ignore by default. These settings can be overridden by CLI options. - -### Watched Files -Watch `.js`, `.json`, and `.jsx` files, the [`config/`](../../../config) directory, [`nodemon.json`](../../../nodemon.json), and [`webpack.config.js`](../../../webpack.config.js). - -### Ignored Files -All `.test.js` and `.test.jsx` files. - -## package.json -[`package.json`](../../../package.json) is the main file that tells npm and Yarn about the project. For more info on the project's [`package.json`](../../../package.json) scripts, read the ["Developing: package.json Scripts" documentation](developing.md#packagejson-scripts). For more info on configuring [`package.json`](../../../package.json), read the [npm "package.json" docs](https://docs.npmjs.com/files/package.json). - -## stylelint -[stylelint](https://stylelint.io) helps identify potential problems and deviations from code style guidelines in your CSS and Sass. The config file can be found in the project's root directory as [`.stylelintrc`](../../../.stylelintrc). For more info on configuring stylelint, read the [stylelint "Configuration" docs](https://stylelint.io/user-guide/configuration). - -### Config Extensions -* [`stylelint-config-recommended`](https://github.com/stylelint/stylelint-config-recommended) -Turns on all [possible errors](https://github.com/stylelint/stylelint/blob/master/docs/user-guide/rules.md#possible-errors) in stylelint. - -### Rules -These specific rules override any rules set by config extensions and will trigger a violation if broken. -* 2 space characters for each indentation -* Line endings must be Unix - -## webpack -[webpack](https://webpack.js.org) builds the project. The config files can be found in the project's root directory as [`webpack.config.js`](../../../webpack.config.js) and within [`config/`](../../../config). For more info on configuring webpack, read the [webpack "Configuration" docs](https://webpack.js.org/configuration). - -### Development -#### Entry -[`webpack.config.js`](../../../webpack.config.js) -```javascript -entry: `${PATHS.src}/main.jsx`, -``` -Start building from `src/main.jsx`. More info can be found in the [webpack "Entry and Context" docs](https://webpack.js.org/configuration/entry-context). - -#### Resolve -[`webpack.config.js`](../../../webpack.config.js) -```javascript -resolve: { extensions: ['.js', '.jsx', '.json'] } -``` -Look for files with `.js`, `.jsx`, or `.json` extensions. More info can be found in the [webpack "Resolve" docs](https://webpack.js.org/configuration/resolve). - -#### Compile JavaScript -[`webpack.config.js`](../../../webpack.config.js) -```javascript -parts.loadJS({ include: PATHS.src }), -``` -Load all JavaScript in `src/` and compile them with Babel using [Babel Loader](https://github.com/babel/babel-loader). - -#### Create HTML -[`webpack.config.js`](../../../webpack.config.js) -```javascript -parts.loadHTML({ template: `${PATHS.src}/index.html` }) -``` -Create an HTML file using the template at `src/index.html` with [HTML Webpack Plugin](https://github.com/jantimon/html-webpack-plugin). - -#### Output -[`config/development.js`](../../../config/development.js) -```javascript -output: { - chunkFilename: '[name].js', - filename: '[name].js', - path: `${PATHS.build}/development` -} -``` -Output bundle at `build/development/` and name the bundled JavaScript `main.js`. More info in the [webpack "Output" docs](https://webpack.js.org/configuration/output). - -#### Delete old build -[`config/development.js`](../../../config/development.js) -```javascript -parts.cleanPaths(['build/development']), -``` -Delete old development build at `build/development/` with [clean-webpack-plugin](https://github.com/johnagan/clean-webpack-plugin). - -#### Setup development server -[`config/development.js`](../../../config/development.js) -```javascript -parts.setupDevServer({ - host: process.env.HOST, - port: process.env.PORT, - historyApiFallback: true, - hot: true -}), -``` -Host [webpack-dev-server](https://github.com/webpack/webpack-dev-server). Host and port are determined by the Node.js `process.env` `HOST` and `PORT` variables respectively. If they are not set, the default host will be set to `localhost` and the port will be set to `8080`. - -`historyApiFallback` is set to `true` to allow use of the [HTML5 History API](https://developer.mozilla.org/en-US/docs/Web/API/History) which allows the use of [React Router's BrowserRouter](https://reacttraining.com/react-router/web/api/browserrouter). - -`hot` is set to `true` to enable webpack's [hot module replacement](https://webpack.js.org/concepts/hot-module-replacement) which allows the use of [React Hot Loader](https://github.com/gaearon/react-hot-loader). - -More info can be found in the [webpack "DevServer" docs](https://webpack.js.org/configuration/dev-server). - -#### Load styles -[`config/development.js`](../../../config/development.js) -```javascript -parts.loadStyles(), -``` -Load all Sass and compile them into CSS using [Sass Loader](https://github.com/webpack-contrib/sass-loader). Then go through possible `@import` and `url()` lookups within all CSS and treat them like an ES2015 `import` or `require()` using [CSS Loader](https://github.com/webpack-contrib/css-loader). Finally inject styling into the DOM using [Style Loader](https://github.com/webpack-contrib/style-loader) so styles can be hot reloaded with webpack-dev-server. Also generate CSS source maps. - -#### Load images -[`config/development.js`](../../../config/development.js) -```javascript -parts.loadImgs(), -``` -Load image files with `.gif`, `.jpg`, `.jpeg`, or `.png` extensions and transform them into base64 URIs which are inlined into the JavaScript bundle using [url-loader](https://github.com/webpack-contrib/url-loader). - -#### Load fonts -[`config/development.js`](../../../config/development.js) -```javascript -parts.loadFonts(), -``` -Load font files with `.eot`, `.tff`, `.woff`, or `.woff2` extensions and transform them into base64 URIs which are inlined into the JavaScript bundle using [url-loader](https://github.com/webpack-contrib/url-loader). - -#### Generate source maps -[`config/development.js`](../../../config/development.js) -```javascript -parts.genSourceMaps({ type: 'cheap-module-eval-source-map' }) -``` -Enable JavaScript source maps with `'cheap-module-eval-source-map'`. More info can be found in the [webpack "Devtool" docs](https://webpack.js.org/configuration/devtool). - -### Production -#### Entry -[`webpack.config.js`](../../../webpack.config.js) -```javascript -entry: `${PATHS.src}/main.jsx`, -``` -Start building from `src/main.jsx`. More info can be found in the [webpack "Entry and Context" docs](https://webpack.js.org/configuration/entry-context). - -#### Resolve -[`webpack.config.js`](../../../webpack.config.js) -```javascript -resolve: { extensions: ['.js', '.jsx', '.json'] } -``` -Look for files with `.js`, `.jsx`, or `.json` extensions. More info can be found in the [webpack "Resolve" docs](https://webpack.js.org/configuration/resolve). - -#### Compile JavaScript -[`webpack.config.js`](../../../webpack.config.js) -```javascript -parts.loadJS({ include: PATHS.src }), -``` -Load all JavaScript in `src/` and compile them with Babel using [Babel Loader](https://github.com/babel/babel-loader). - -#### Create HTML -[`webpack.config.js`](../../../webpack.config.js) -```javascript -parts.loadHTML({ template: `${PATHS.src}/index.html` }) -``` -Create an HTML file using the template at `src/index.html` with [HTML Webpack Plugin](https://github.com/jantimon/html-webpack-plugin). - -#### Output -[`config/production.js`](../../../config/production.js) -```javascript -output: { - chunkFilename: '[name].[chunkhash:4].js', - filename: '[name].[chunkhash:4].js', - path: `${PATHS.build}/production` -} -``` -Output bundle at `build/production/` and name the bundled JavaScript `main.[chunkhash].js`. All other built files will follow the `[name].[chunkhash:4].[ext]` format in their filenames. The part of the chunkhash in the filename is used as a fingerprint to allow for [cache invalidation](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#invalidating_and_updating_cached_responses). More info in the [webpack "Output" docs](https://webpack.js.org/configuration/output). - -#### Delete old build -[`config/production.js`](../../../config/production.js) -```javascript -parts.cleanPaths(['build/production']), -``` -Delete old development build at `build/production/` with [clean-webpack-plugin](https://github.com/johnagan/clean-webpack-plugin). - -#### Check types -[`config/production.js`](../../../config/production.js) -```javascript -parts.checkTypes(), -``` -Check types in JavaScript with Flow using [flow-webpack-plugin](https://github.com/happylynx/flow-webpack-plugin). - -#### Minify JavaScript -[`config/production.js`](../../../config/production.js) -```javascript -parts.minJS(), -``` -Minify JavaScript with [UglifyJS](http://lisperator.net/uglifyjs) using the [UglifyJS Webpack Plugin](https://github.com/webpack-contrib/uglifyjs-webpack-plugin). - -#### Minify CSS -[`config/production.js`](../../../config/production.js) -```javascript -parts.minCSS({ - options: { - discardComments: { removeAll: true }, - safe: true - } -}), -``` -Minify CSS with [Optimize CSS Assets Webpack Plugin](https://github.com/NMFR/optimize-css-assets-webpack-plugin) using [cssnano](https://cssnano.co) while discarding all comments and running in safe mode to avoid potentially unsafe transformations. - -#### Load and extract styles -[`config/production.js`](../../../config/production.js) -```javascript -parts.extractStyles({ - filename: '[name].[contenthash:4].css', - use: ['css-loader', 'sass-loader', parts.autoprefix()] -}), -``` -First use [PostCSS Loader](https://github.com/postcss/postcss-loader) with the [Autoprefixer](https://github.com/postcss/autoprefixer) plugin to parse styles and add vendor prefixes based on targeted browsers in the project's Browserslist. Then load all Sass and compile them into CSS using [Sass Loader](https://github.com/webpack-contrib/sass-loader). Then go through possible `@import` and `url()` lookups within all CSS and treat them like an ES2015 `import` or `require()` using [CSS Loader](https://github.com/webpack-contrib/css-loader). - -Finally separate CSS into its own file called `main.[contenthash:4].css` using [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin). Like the chunkhash used in the output option, part of the contenthash is used as a fingerprint to allow for [cache invalidation](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#invalidating_and_updating_cached_responses). The reason why styles use contenthashes instead of chunkhashes is because using chunkhashes would cause both JavaScript and CSS files to invalidate if either is edited. For example, in this scenario if you were to only edit your style source, the JavaScript bundles would become invalidated as well even though the JavaScript source has not changed. By using contenthashes we can avoid this problem by separating them and making sure JavaScript and CSS fingerprints are independent of each other, ensuring their caches remain valid as long as possible. - -#### Delete unused CSS -[`config/production.js`](../../../config/production.js) -```javascript -parts.purifyCSS({ paths: glob.sync(`${PATHS.src}/**/*.{js,jsx}`, { nodir: true }) }), -``` -Remove unused selectors in CSS using [PurifyCSS Plugin](https://github.com/webpack-contrib/purifycss-webpack). - -#### Load images -[`config/production.js`](../../../config/production.js) -```javascript -parts.loadImgs({ - options: { - name: `${PATHS.assets}/imgs/[name].[hash:4].[ext]` - }, - type: 'file' -}), -``` -Load image files with `.gif`, `.jpg`, `.jpeg`, or `.png` extensions and output them in `/assets/imgs/` with [file-loader](https://github.com/webpack-contrib/file-loader). - -#### Load fonts -[`config/production.js`](../../../config/production.js) -```javascript -parts.loadFonts({ - options: { - name: `${PATHS.assets}/fonts/[name].[hash:4].[ext]` - }, - type: 'file' -}), -``` -Load font files with `.eot`, `.tff`, `.woff`, or `.woff2` extensions and output them in `/assets/imgs/` with [file-loader](https://github.com/webpack-contrib/file-loader). - -#### Generate source maps -[`config/production.js`](../../../config/production.js) -```javascript -parts.genSourceMaps({ type: 'source-map' }), -``` -Enable JavaScript source maps with `'source-map'`. More info can be found in the [webpack "Devtool" docs](https://webpack.js.org/configuration/devtool). - -#### Bundle splitting, manifest, and records -[`config/production.js`](../../../config/production.js) -```javascript -{ - optimization: { - splitChunks: { - cacheGroups: { - commons: { - name: 'vendor', - chunks: 'initial', - test: /[\\/]node_modules[\\/]/ - } - } - }, - runtimeChunk: { name: 'manifest' } - }, - - recordsPath: `${PATHS.root}/records.json` -} -``` -1. Separate dependencies in `node_modules/` into `vendor.[chunkhash:4].js`. -2. Create manifest to have webpack load the project faster instead of waiting for the vendor bundle to be loaded. -3. Create `records.json` to store module IDs across separate builds. This allows the generation of longer lasting filenames, makes sure that code split parts gain correct caching behavior, and that modules aren't reordered or moved to another chunk during the bundling process which results to less cache invalidations. \ No newline at end of file diff --git a/docs/envs/browser/dependencies.md b/docs/envs/browser/dependencies.md deleted file mode 100644 index b9455446..00000000 --- a/docs/envs/browser/dependencies.md +++ /dev/null @@ -1,122 +0,0 @@ -# Web Browser: Dependencies -To check versions for dependencies, view [`package.json`](../../../package.json). - -## Production -* [**`cross-fetch`**](https://npmjs.com/package/cross-fetch) -Universal fetch API for browsers and Node.js. Chosen over other solutions so fetch API dependency can be consistent across all environments. -* [**`prop-types`**](https://npmjs.com/package/prop-types) -Type checking for `react` props. Recommended for use when `flow-bin` isn't being used. -* [**`react`**](https://npmjs.com/package/react) -User interface library -* [**`react-dom`**](https://npmjs.com/package/react-dom) -Entry point to the DOM for `react` -* [**`react-hot-loader`**](https://npmjs.com/package/react-hot-loader) -Update `react` components without refreshing the browser while maintaining state -* [**`react-redux`**](https://npmjs.com/package/react-redux) -`react` bindings for `redux` -* [**`react-router-dom`**](https://npmjs.com/package/react-router-dom) -Routing library for `react` -* [**`redux`**](https://npmjs.com/package/redux) -State management library - -## Development -* [**`@babel/core`**](https://npmjs.com/package/@babel/core) -JavaScript compiler -* [**`@babel/plugin-proposal-class-properties`**](https://npmjs.com/package/@babel/plugin-proposal-class-properties) -[`@babel/core` plugin that transforms static class properties as well as properties declared with the property initializer syntax](https://babeljs.io/docs/en/next/babel-plugin-proposal-class-properties.html) -* [**`@babel/preset-env`**](https://npmjs.com/package/@babel/preset-env) -[`@babel/core` smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms (and optionally, browser polyfills) are needed by your target environments](https://babeljs.io/docs/en/next/babel-preset-env.html) -* [**`@babel/preset-flow`**](https://npmjs.com/package/@babel/preset-flow) -[`@babel/core` preset for all `flow-bin` plugins](https://babeljs.io/docs/en/next/babel-preset-flow.html) -* [**`@babel/preset-react`**](https://npmjs.com/package/@babel/preset-react) -[`@babel/core` preset for all `react` plugins](https://babeljs.io/docs/en/next/babel-preset-react.html) -* [**`autoprefixer`**](https://npmjs.com/package/autoprefixer) -`postcss` plugin that adds vendor prefixes to styles based on what you need for your target environments -* [**`babel-core`**](https://npmjs.com/package/babel-core) -Duplicate of `@babel/core`, but is needed for some older Babel related dependencies. -* [**`babel-eslint`**](https://npmjs.com/package/babel-eslint) -Parser for `eslint` that enables linting of all `@babel/core` code, particularly for `flow-bin` -* [**`babel-jest`**](https://npmjs.com/package/babel-jest) -`jest` plugin for `@babel/core` -* [**`babel-loader`**](https://npmjs.com/package/babel-loader) -`webpack` loader that allows transpiling of JavaScript files using `@babel/core` -* [**`clean-webpack-plugin`**](https://npmjs.com/package/clean-webpack-plugin) -`webpack` plugin used for removing build folders before new build -* [**`css-loader`**](https://npmjs.com/package/css-loader) -`webpack` loader that interprets @import and url() like import/require() and will resolve them -* [**`cssnano`**](https://npmjs.com/package/cssnano) -Modular compression tool used with `optimize-css-assets-webpack-plugin` to minify styles -* [**`deep-freeze`**](https://npmjs.com/package/deep-freeze) -Disable mutations on objects. Mainly used for testing `redux` reducers to ensure they are pure functions. -* [**`enzyme`**](https://npmjs.com/package/enzyme) -Testing utility for `react` that makes it easier to assert, manipulate, and traverse your `react` components' output -* [**`enzyme-adapter-react-16`**](https://npmjs.com/package/enzyme-adapter-react-16) -`enzyme` adapter to test with `react` 16 -* [**`enzyme-to-json`**](https://npmjs.com/package/enzyme-to-json) -Convert `enzyme` wrappers to a format compatible with `jest` snapshot testing -* [**`eslint`**](https://npmjs.com/package/eslint) -JavaScript linter -* [**`eslint-plugin-flowtype`**](https://npmjs.com/package/eslint-plugin-flowtype) -`eslint` plugin that enables linting for `flow-bin` -* [**`eslint-plugin-jest`**](https://npmjs.com/package/eslint-plugin-jest) -`eslint` plugin that enables linting for `jest` -* [**`eslint-plugin-react`**](https://npmjs.com/package/eslint-plugin-react) -`eslint` plugin that enables linting for `react` -* [**`file-loader`**](https://npmjs.com/package/file-loader) -`webpack` loader that loads assets -* [**`flow-bin`**](https://npmjs.com/package/flow-bin) -Type checker -* [**`flow-typed`**](https://npmjs.com/package/flow-typed) -Repository of third-party `flow-bin` library interface definitions -* [**`flow-webpack-plugin`**](https://npmjs.com/package/flow-webpack-plugin) -`webpack` plugin that calls `flow-bin` during each production build -* [**`glob`**](https://npmjs.com/package/glob) -Match files using the patterns the shell uses -* [**`html-webpack-plugin`**](https://npmjs.com/package/html-webpack-plugin) -`webpack` plugin that generates HTML files -* [**`http-server`**](https://npmjs.com/package/http-server) -Web server used for previewing production builds -* [**`jest`**](https://npmjs.com/package/jest) -JavaScript tester -* [**`jsdom`**](https://npmjs.com/package/jsdom) -JavaScript-based headless browser used in testing with `jest` -* [**`mini-css-extract-plugin`**](https://npmjs.com/package/mini-css-extract-plugin) -Extract styles into separate files -* [**`node-sass`**](https://npmjs.com/package/node-sass) -Extend CSS functionality -* [**`nodemon`**](https://npmjs.com/package/nodemon) -Restart Node.js applications when file changes are detected -* [**`optimize-css-assets-webpack-plugin`**](https://npmjs.com/package/optimize-css-assets-webpack-plugin) -Minify styles with `cssnano` -* [**`postcss`**](https://npmjs.com/package/postcss) -Transform styles with JavaScript plugins. Used with `autoprefixer`. -* [**`postcss-loader`**](https://npmjs.com/package/postcss-loader) -`webpack` loader that processes styles with `postcss` -* [**`purify-css`**](https://npmjs.com/package/purify-css) -Delete unused styles in production build -* [**`purifycss-webpack`**](https://npmjs.com/package/purifycss-webpack) -`webpack` plugin for `purify-css` -* [**`react-test-renderer`**](https://npmjs.com/package/react-test-renderer) -Test renderer for `react` components -* [**`redux-mock-store`**](https://npmjs.com/package/redux-mock-store) -Mock store for testing `redux` asynchronous action creators and middleware -* [**`sass-loader`**](https://npmjs.com/package/sass-loader) -`webpack` loader to compile `node-sass` into CSS -* [**`style-loader`**](https://npmjs.com/package/style-loader) -`webpack` loader that adds CSS to the DOM by injecting a `