Migrate a project from ES6 to Typescript

I few days ago I started a migration of a project from ES6 to Typescript.

The main job is doing by a few configuration files.


tsconfig.json

  • The most important file.
  • This one tell to the Typescript compiler tsc in what way and which files need to compile.
{
  "compilerOptions": {
    "target": "es2015",
    "declaration": true,
    "sourceMap": true,
    "moduleResolution": "node",
    "declarationDir": "./public",
    "allowSyntheticDefaultImports": true,
  },
  "include": [
    "src/**/*"
  ]
}

webpack.config.js

  • The Webpack configuration only has one plugin: ts-loader
  • The ts-loader plugin apply the configuration of tsconfig.json and execute the Typescript compiler.
  • This task will be called later by the build and the dev scripts (both of them stored on package.json)
  • So, for resuming:

    • ts-loader will compile all the .js and .ts files (from the path src) to ES215/UMD format (this project doesn’t need Babel anymore!)
    • And then put the result into the public folder:

      public/index.js
      public/index.js.map
      public/types.d.ts
      # and more files...
    • index.js is the file that any app that use the library will consume.
const path = require('path');
const webpack = require('webpack');

const PATHS = {
  src: path.join(__dirname, './src'),
  dist: path.join(__dirname, './public')
}

module.exports = {
  mode: process.env.mode,
  entry: {
    "index": PATHS.src + "/index.ts"
  },
  output: {
    path: PATHS.dist,
    filename: "index.js",
    libraryTarget: "umd",
    libraryExport: 'default',
    library: 'NAME_OF_THE_LIBRARY',
  },
  devtool: "source-map",
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: "ts-loader"
      },
    ]
  },
  resolve: {
    extensions: [".ts", ".js"]
  },
  plugins: [
    new webpack.IgnorePlugin(/test\.ts$/)
  ]
}

.eslintrc

  • The ESLint configuration, for maintain a codebase free of syntax errors and also for follow a common style guide.

Javascript files

We apply these plugins to the Javascript files:

  • eslint:recomended
  • jsdoc/recomended

Typescript files

We apply these plugins to the Typescript files:

  • eslint:recomended
  • jsdoc/recomended
  • @typescript-eslint/eslint-recommended
{
  "root": true,
  "env": {
    "es6": true,
    "node": true
  },
  "extends": [
    "eslint:recommended",
    "plugin:jsdoc/recommended"
  ],
  "parser": "babel-eslint",
  "plugins": [
    "jsdoc"
  ],
  "parserOptions": {
    "ecmaVersion": 6,
    "sourceType": "module"
  },
  // Temporal workaround because this project will has
  // for a while files in format .js and .ts.
  "overrides": [
    {
      "files": [
        "**/*.ts"
      ],
      "env": {
        "es6": true,
        "node": true
      },
      "extends": [
        "eslint:recommended",
        "plugin:jsdoc/recommended",
        "plugin:@typescript-eslint/eslint-recommended",
        "plugin:@typescript-eslint/recommended"
      ],
      "parser": "@typescript-eslint/parser",
      "plugins": [
        "jsdoc",
        "@typescript-eslint"
      ]
    }
  ]
}

.eslintignore

  • The ESLint ignore configuration
  • You can tell ESLint to ignore specific files and directories.
  • In this case we ignore node_modules and public folders.
node_modules
public
coverage

package.json

Here you can find all the scripts of the app and also the dependencies and more metadata of the app.

Build

  • "build": "webpack --mode=production"
  • This script builds the app for the production environment.
  • This script will be called later by Gitlab for deploy the app to production (configuration stored on .gitlab-ci.yml)

Dev

  • "dev": "webpack --mode=development --watch"
  • This script builds the app for the development environment.

Linters

  • lint:js and lint:ts
  • Both scripts read the .eslintrc file and apply the configuration.
  • Both scripts will be called later by Gitlab for testing the app before deploy it to production (configuration stored on .gitlab-ci.yml)

Unit tests

  • test:unit
  • This script compile the library before call Jest.
  • This is because, all the unit tests only validate the compiled version of the library.
{
  "scripts": {
    "prepare": "npm run build",
    "build": "webpack --mode=production",
    "dev": "webpack --mode=development --watch",
    "lint:js": "eslint 'src/**/*.js'",
    "lint:ts": "eslint 'src/**/*.ts'",
    "docs": "esdoc",
    "test:unit": "yarn build && jest --notify --verbose"
  },
}

.gitlab-ci.yml

GitLab CI/CD pipelines are configured using a YAML file called .gitlab-ci.yml within each project.

stages:
  - test
  - deploy

image: node:latest

before_script:
  - curl -o- -L https://yarnpkg.com/install.sh | bash
  - export PATH=${HOME}/.yarn/bin:${PATH}
  
cache:
  paths:
    - node_modules/
  
library test:
  stage: test
  script:
    - yarn
    - yarn test:unit
    - yarn lint:js
    - yarn lint:ts

pages:
  stage: deploy
  script:
    - yarn docs
    - yarn build
  artifacts:
    paths:
    - public
  only:
  - master