DEV Community

Hossomi
Hossomi

Posted on • Edited on

Frontline: Preparing Grounds

Hello everyone! A long time after the first post, it's time to roll up the sleeves and start coding.

Before anything else, I like to prepare the project structure and build. The logical first step is installing Yarn and Typescript and get it to build anything.

In this article | Repository | Changes | Final commit

Setting up Yarn

To install Yarn, it is recommended to use Corepack, bundled with Node starting in 16.10. It seems to be an all-in-one package manager, and it already includes Yarn out of the box. All you need to do is run corepack enable (since it is experimental and disabled by default) and then yarn init -2 to initialize a new project.

โ„น -2 ensures that it uses Yarn 2+ (modern), required to work with zero-installs. More on it later!

As I mentioned, I want to use Yarn workspaces to organize modules. Each module needs its own package.json file, so let's start with the following structure:

๐Ÿ“ฆtamiyo
 โ”ฃ ๐Ÿ“‚client
 โ”ƒ โ”— ๐Ÿ“œpackage.json
 โ”ฃ ๐Ÿ“‚server
 โ”ƒ โ”— ๐Ÿ“œpackage.json
 โ”ฃ ๐Ÿ“‚shared
 โ”ƒ โ”— ๐Ÿ“œpackage.json
 โ”— ๐Ÿ“œpackage.json
Enter fullscreen mode Exit fullscreen mode

The package.json content is mostly the usual, the difference being that the parent file contains a workspaces field specifying where the workspaces are:

 {
  "name": "tamiyo",
  "version": "1.0.0",
  "packageManager": "yarn@3.2.0",
  "workspaces": [
    "server",
    "client",
    "shared"
  ]
}
Enter fullscreen mode Exit fullscreen mode

For the modules, we are prefixing their package names with @tamiyo for consistency. The client file for example is like this:

{
  "name": "@tamiyo/client",
  "version": "1.0.0",
  "packageManager": "yarn@3.2.0"
}
Enter fullscreen mode Exit fullscreen mode

Running yarn install makes sure we've setup correctly, and you'll notice it creates some files. The yarn.lock is well known, and the others are related to Yarn's zero-installs: .yarnrc.yml, .pnp.cjs and the .yarn directory. With all these checked into the repository, you no longer need to run this command unless dependencies change (hence zero installs)! Read the documentation for more advantages of this mechanism.

Setting up Typescript

Let's get started with Typescript! The first thing to do is to install it with yarn add -D typescript. It will install the tsc CLI tool that we can run with yarn tsc to compile Typescript code into Javascript, making it runnable in broswers, node and the like.

Typescript is organized in projects, indicated by a tsconfig.json file along with various project settings. It can also be divided into smaller subprojects, which pairs well with the Yarn workspaces we are using! We just have to place a tsconfig.json file in each workspace as well.

๐Ÿ“ฆtamiyo
 โ”ฃ ๐Ÿ“‚client
 โ”ƒ โ”ฃ ๐Ÿ“œpackage.json
 โ”ƒ โ”— ๐Ÿ“œtsconfig.json
 โ”ฃ ๐Ÿ“‚server
 โ”ƒ โ”ฃ ๐Ÿ“œpackage.json
 โ”ƒ โ”— ๐Ÿ“œtsconfig.json
 โ”ฃ ๐Ÿ“‚shared
 โ”ƒ โ”ฃ ๐Ÿ“œpackage.json
 โ”ƒ โ”— ๐Ÿ“œtsconfig.json
 โ”ฃ ๐Ÿ“œpackage.json
 โ”— ๐Ÿ“œtsconfig.json
Enter fullscreen mode Exit fullscreen mode

The root tsconfig.json is special: it has a references property specifying the subprojects, which in our case are the workspaces. We also specify "include": [] so that the root project doesn't build anything, since it's not a module itself.

{
  "references": [
    { "path": "./shared" },
    { "path": "./client" },
    { "path": "./server" }
  ],
  "include": []
}
Enter fullscreen mode Exit fullscreen mode

The workspaces are where actual code resides, so their tsconfig.json contains compiler options:

{
  "compilerOptions": {
    "rootDir": "src",
    "outDir": "build",

    "target": "es6",
    "strict": true,
    "noFallthroughCasesInSwitch": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "composite": true,
    "esModuleInterop": true,
    "isolatedModules": false,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true
  }
}
Enter fullscreen mode Exit fullscreen mode

You can see their meaning in the TSConfig reference. It's important to note that composite: true is required when using Typescript subprojects. To avoid repeating all those properties in each workspace, we can extract them to a common tsconfig.common.json and make the workspaces extend them:

# ./tsconfig.common.json
{
  "compilerOptions": {
    "target": "es6",
    "strict": true,
    "noFallthroughCasesInSwitch": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "composite": true,
    "esModuleInterop": true,
    "isolatedModules": false,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true
  }
}

# {module}/tsconfig.json
{
  "extends": "../tsconfig.common.json",
  "compilerOptions": {
    "rootDir": "src",
    "outDir": "build"
  }
}
Enter fullscreen mode Exit fullscreen mode

With that, we should be able to build from the root directory. Let's put a simple file under the src directory of each module to test it out:

// {module}/src/index.ts
console.log('Hello!')
Enter fullscreen mode Exit fullscreen mode

Running yarn tsc --build --verbose should compile all the Typescript files and generate .d.ts and .js files under {module}/build directories, as we instructed in the configuration. These files are what will be actually run by either Node, browser and the like.

Next step

Our project can at least be compiled! Next, it is time to get something up and running. As I mentioned, I will use Create React App to build our client, providing us a quick lift. We'll also see how we can implement and integrate our server with it.

Top comments (0)