A vanilla Typescript Babel Boilerplate
TLDR; Github repo
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