A vanilla Typescript Babel Boilerplate

TLDR; Github repo

minipic - Vanilla Typescript Babel Boilerplate

Today I’m working on a web SDK that uses Typescript. I’ve worked on a new boilerplate for this project, since the vanilla Javascript boilerplate I have has at least 6 or more years; Suprisingly, because I didn’t want to reinvent the wheel, while looking around for a vanilla TS project + common practicies, I found that most options that exist are of React boilerplate with Typescript; there are probably some obscure projects I don’t know about or that are hard to find (did a Github search but didn’t find anything relevant for my needs) but happen to not fulfill the requirements for the project I have in hands. Similarily, I do have my own React Typescript boilerplate and could have instead pick that up to tackle the projet requirements immediately, but I’ve opted to keep it as minimal as possible and not have React/VUE/Angular.

I’ll drop a few notes that I came up during the development of this project bellow.

To start, I’ve decided to have live reload in the project and a very simple css pre-processor.

For live-reloading, noticed that there aren’t any new live reload projects since the old live reload apart from the common Webpack/Rollup/Parecel options or plugins in the market. If you think about it, more then 5 or 6 years ago, browsersync was used daily - but today, the project hasn’t been updated for awhile, so that definitely says a lot about what people have been into for the past few years.

End up deciding to use Webpack, but spent some time testing Rollupjs that I personally didn’t enjoy, and feel that just wasted time - maybe next time I’ll test Parceljs?

CSS does not necessarily need a whole essay, but I’ve picked node-sass for no other reason thensimplicity and no semicolons - actually started with Stylus but the Webpack stylus-loader, is not a good fit. Nowadays I use css-in-js libraries such as styled-component, etc or provide support for earlier applications that use css-modules, even though I’m coming from a sass background, that I used to work with in Angularjs, and vanilla javascript projects back in the days.

Static type checking#

The project will require me to do static type checking, at a lexical level and not during runtime - this is only during development as my text editor through Typescript will provide me some code insights, code completion, etc but it does not guard any underlying javascript runtime issues. For that, I use Typescript but use Babel to transpile the code to my target audience, so Typescript does not emit any Javascript. Here is my take on how to setup:

yarn add --dev
  typescript \
  @babel/core \
  @babel/cli \
  @babel/preset-env \
  @babel/preset-typescript

Nowadays Babel has moved from the classic .babelrc file to either babel.config.js, or its definitions in the projects package.json.

My advice is to always refer to the original Babel documentation, as back in early 2019 or late 2018 when this changes were published, there was some confusion about how to implement it correctly. And I think we can still use the old way.

The Typescript configuration file tsconfig.json for my particular use case, looks like:

{
  "compilerOptions": {
    "strict": true,
    "target": "esnext",
    "moduleResolution": "node",
    "noEmit": true,
    "esModuleInterop": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": [
    "src"
  ]
}

Again, use the Typescript documentation to find more information about your particular use case and change accordingly.

Nevertheless, have in mind a few settings that I have declared.

Transpiler#

I target esnext which means that I decided to usethe latest ECMAScript proposed features (experimentals, etc). Alternatively, you may want to pick other ECMAScript versions, such as ES5, ES6 or ES2015 - but this wouldn’t make much sense since I’ll have Babel to transpile the source-code. Have this in mind, I use the latest available features in Typescript while developing, where separately for distribution Babel computes to the desired ECMAScript version.

Because Babel is transpiling the Tyepscript code for me, the use of modern ES might fail when pass the babel-loader. For example using option chaining fail so had to add the plugin for Babel (atention that its alright in Typescript, this might be confusing if you are not following):

  "babel": {
    "presets": [
      "@babel/preset-env",
      "@babel/preset-typescript"
    ],
    "plugins": [
      "@babel/plugin-proposal-optional-chaining"
    ]
  }

To complete, the scripts or tasks defined in my package.json are a watch and build process. As follows:

  "scripts": {
    "build:js": "npx webpack --env.NODE_ENV=production --progress --colors --config ./bundler/webpack.common.js",
    "build": "npm run build:js",
    "start:webpack-dev-server": "npx webpack-dev-server --env.NODE_ENV=development --progress --colors --config ./bundler/webpack.common.js"
  }

This should read, run the local version of Babel (that’s what npx means) and read from the source directory src and output the computed transpiled files to ./dist; the remaining flags are optional and you should check the documentation to know more or run the babel man or --help.

Now, it’s important to understand that if we were solely using the TSC we could target a particlar ES version as stated above; since we not using TSC for it, let’s look at how this is done in Babel.

For my Babel target definition, I use the suggest method that is .browserslistrc, that is documented in the offical docs - you can find it here .

You may opt to use the package.json to declare this information or create a file called .browserslistrc. I believe that the method I use for the Babel presets should be the same here and have it in the package.json.

  "browserslist": {
    "production": [
      "last 3 chrome version",
      "last 3 firefox version"
    ]
  }

The browserlist uses environment variables to determinate which case to use, but it fallsback to NODE_ENV, if BROWSERSLIST_ENV not available. For a boilerplate, I’ll just have production but this can be extended or changed according to each project need.

CSS Pre-processor#

As stated above I’ve opted to use sass for the simplicity it provides, but any other css pre processor can be used in place, the principles are similar.

Distribution#

The setup I have gives me control over the versioning of the static files:

  /dist
    /project-name
      /version
          /css/main.min.css
          /js/main.min.js 

You can find the repository for this project at: Vanilla Typescript Boilerplate

comments powered by Disqus