This repository contains the Node.js project for the website. It is deployed as static content to a web server.
…/disw-web-app> git config user.name "<first name> <last name>" …/disw-web-app> git config user.email "<id+username>@users.noreply.github.com"
This project uses the zero-install feature of the Yarn package manager.
Upon cloning the Git repository, the .yarn/cache
directory already contains a cache of the third-party dependencies, effectively replacing the usual node_modules
directory.
Open the project directory into which you cloned the repository: menu:File[Open].
Caution
|
You should not import the project or create a new project from existing sources. |
Adjust the inspection settings to disable false positive warnings:
-
Open the inspection settings: menu:File[Settings > Editor > Inspections].
-
Disable warnings from this inspection:
-
menu:JavaScript and TypeScript[Imports and dependencies > Missing 'React' namespace import in JSX code].
-
Specify a pattern of files to exclude from indexing:
-
Open the project module settings: menu:File[Project Structure > Modules].
-
For the
disw-web-app
module, set Exclude files to.asciidoctor*;.editorconfig;.eslint*;.git*;.pnp*;*yarn*
.
A profile describes the content to display in the web app.
It defines three components: HeaderContent
, MainContent
, and FooterContent
.
A reference implementation is available in perserverance-dummy.tsx
.
The VITE_PROFILE_NAME
environment variable specifies the profile to use.
It is defined in .env.development
.
You can create a new profile:
-
In the
main/content
directory, create a TypeScript file named e.g.my-profile.local.tsx
which must export the name to be displayed in the title bar, a description for search engines and web browsers, and three function components:import { Hero, Main, Footer } from "+profile" export const name = "My Profile Name" export const description = "An accurate summary of the page content." export function HeaderContent() { return ( <Hero> ... </Hero> ) } export function MainContent() { return ( <Main> ... </Main> ) } export function FooterContent() { return ( <Footer> ... </Footer> ) }
-
In the
main/content
directory, create a new directory namedassets.local
to contain image assets for the hero and the occupation timeline of the profile page. Use theHeroImage
andThemedArticleImage
components to encapsulate the image assets in their own components. Provide images in multiple sizes to accommodate responsive design. Encode the images as WebP files and provide a JPEG file as a fallback. -
In the project root directory, create a new file named
.env.development.local
(or.env.production.local
when building for production). Override theVITE_PROFILE_NAME
environment variable to use the new profile by specifying the name of the TypeScript file without the.tsx
extension:VITE_PROFILE_NAME=my-profile.local
Important
|
The Git repository in this project ignores files and directories whose names contain the substring |
Tip
|
When switching between profiles in Uncaught Error: Hook can only be invoked from render methods. You can resolve this error by restarting the development server. |
The scripts
field in package.json
defines a set of daily work tasks.
Corresponding IntelliJ IDEA configurations are located in .idea/runConfigurations
.
Run the develop
configuration in IntelliJ IDEA to serve the web app in development, or execute:
…/disw-web-app> yarn run develop
Visit one of the addresses printed in the console in a web browser.
Use http://localhost:8000 when you want to access the web app from your local computer, or use the LAN IP address (usually something like 192.168.X.Y
) when you want to access it from another device.
Equipped with hot module replacement (HMR), it reflects any changes you make in the source code immediately in the web browser.
Run the validate
configuration in IntelliJ IDEA to validate the quality of the software, or execute:
…/disw-web-app> yarn run validate
It runs the following means of validation:
-
Type checking via TypeScript (
validate:type-check
). -
Static program analysis (linting) via ESLint (
validate:lint
). -
Automated unit testing via Vitest (
validate:unit-test
).
The validate:lint:fix
configuration applies an automated fix of certain issues reported by ESLint.
The validate:unit-test:watch
configuration makes the unit test suite run continuously (i.e. in 'watch' mode).
Run the build
configuration in IntelliJ IDEA to make a production-grade distribution of the web app, or execute:
…/disw-web-app> yarn run build
It saves the output in the build/www
directory.
Caution
|
The software validation criteria must pass before it attempts to build the distribution. The |
The build:preview
configuration serves a preview of the generated distribution at http://localhost:80.
Following the Node.js convention, this project distinguishes between runtime dependencies and development dependencies.
The dependencies
and devDependencies
fields in package.json
declare these two sets of dependencies, respectively.
Tip
|
A dependency is a runtime dependency when it is imported by the production source code. For example, |
Use the custom dependenciesComments
and devDependenciesComments
fields to associate each dependency to a maintenance comment or a description that justifies its use in this project.
Preferably, runtime dependencies should not have any transitive dependencies.
Important
|
For security reasons, always specify the exact version of a dependency in Avoid using the |
To update a third-party dependency to its latest version, execute these two commands:
…/disw-web-app> yarn up --exact <dependency> …/disw-web-app> yarn up --recursive <dependency>
Preact is a reactive web UI framework with an API similar to that of React. It lets you define components as JavaScript functions using JSX.
Caution
|
The JSX dialect of Preact is slightly different from React. For historical reasons, most tools support JSX transformations for React, compiling JSX to function calls of However, in Preact, the factory function is |
Tailwind CSS is a utility-first CSS framework. It encourages the developer to reuse styles by extracting components (e.g. via Preact) rather than defining CSS rules and abstractions as practised in traditional CSS development.
tailwind.config.cjs
defines the configuration of the Tailwind CSS environment.
Tip
|
The .cjs file extension indicates that the JavaScript file follows the CommonJS module standard of Node.js instead of the modern ECMAScript module standard (ESM).
The latter is usually indicated by the .mjs file extension.
|
PostCSS is a processing tool for CSS.
Among other things, it permits the use of CSS syntax extensions such as the @tailwind
and @apply
directives from Tailwind CSS.
postcss.config.cjs
defines the configuration of PostCSS as recommended by the Tailwind CSS documentation.
TypeScript is a programming language that extends JavaScript with syntax for static typing.
tsconfig.json
defines the configuration of the TypeScript environment, except for the set of globally visible types which global.d.ts
defines.
Vite is a frontend build tool. It hosts the development server and generates the distribution of the web app for production.
vite.config.ts
defines the configuration of Vite.
It picks up the PostCSS configuration in postcss.config.cjs
automatically.
Caution
|
You can define the configurations of PostCSS and Tailwind CSS directly in the Vite configuration file. However, doing so would prevent Vite from instantly applying configuration changes, particularly in Tailwind CSS themes, without requiring a restart of the development server. |
To load the correct profile into the web app, the Vite configuration defines +content
to be an alias for the TypeScript module designated by VITE_PROFILE_NAME
.
Generating a production-grade distribution of the web app consists of two phases:
-
A server-oriented build which produces a CommonJS module that generates static HTML from the initial state of the web app. The entry point is
main-server.tsx
. Vite operates inssr
mode during this phase. -
A client-oriented build which pre-renders the HTML page and produces a browser script that makes the web app interactive. The entry point is
index.html
, which in turn importsmain-client.tsx
. Vite operates in its normal mode during this phase. Additionally, the Vite configuration imports the CommonJS module produced by the server-oriented build to complete pre-rendering the HTML page at build-time.
Note
|
Pre-Rendering, also known as Static Site Generation (SSG), is a technique in which a static HTML page is generated at build-time. Server-Side Rendering (SSR) is a slightly different technique in which the HTML page is generated dynamically by the web server at request-time. Both techniques allow search engines to discover the contents of the web app without having to execute any browser scripts. |
If you need to debug the production-grade distribution, you can set VITE_DEBUG_PRODUCTION_BUILD=true
in .env.production.local
.
This enables Preact debugging tools on runtime and skips minification of the build artifacts.
Vitest is a unit testing framework for JavaScript. It relies on Vite to support TypeScript, JSX, and PostCSS. Its API is largely compatible with that of Jest.
The test
field in vite.config.ts
defines the configuration of Vitest.
ESLint is a static program analysis tool that flags issues in the source code.
.eslintrc.cjs
defines the configuration of ESLint, including the set of rules to be enforced.
It uses TypeScript ESLint to parse TypeScript sources and perform type-aware analysis according to tsconfig.json
.
Caution
|
Every rule must be set to either error or off .
We do not use the warning level, as it would only pollute the linting report while allowing rules to be violated without interrupting the build step.
|
AsciiDoc is a markup language for writing documentation. AsciiDoctor is a processing tool that converts AsciiDoc files to various output formats such as HTML and PDF.
No configuration is needed for accessing the AsciiDoc documentation files in plain text.
Tip
|
IntelliJ IDEA users with the AsciiDoc plugin may customise the HTML preview by providing a stylesheet:
The configuration file and the stylesheet should not be checked into the Git repository. By refraining from doing so, developers may provide their own stylesheet to suit their preference, for example to match a light or a dark theme in IntelliJ IDEA. |