JS ecosystem

Understanding the history of tools

  • In early 2000's, Web apps were simple with limited number of java script and css files. We used to embed JS in html document.
  • As the web apps grew in size, there was a need to put the JS in separate files and then include them in html using script tag's src attribute. Order of the files was important. e.g. If there are 2 files and objects in file1 are being used in file2, then you must include file1 before file2. So this was an issue in large projects. In large project, there are many js files and loading them separately means it was causing network bottleneck. Also If we combine all files in single file, there were issues like scoping and maintainability. IIFE solves the problem of scoping to some extent but script ordering issue still exists. Around same time, task runner tools like Make, Gulp, Grunt came into existence.
  • With IIFE, we were also not able to do code optimizations like lazy loading, tree shaking. Around 2009, NodeJS and common JS module system was introduced. But browsers would not understand this module system and hence it led to birth of tools like Browserify, RequireJS, SystemJS etc. Apart from commonjs, AMD module system was also in use. So we needed a tool that could work with AMD as well as CommonJS.
  • So webpack was invented in 2012 to solve above problems. Webpack will pack all files (including js from different module types, ts, tsx, jsx, css, images and that's possible due to the loaders like css-loader, style-loader, babel-loader, ts-loader) required by html page. So webpack became very popular. Developers do not have to maintain the order of js files included in the html. If you have used react/nextjs, you are already using webpack.
  • In 2015, new features were added in JS. But not all JS engines in browsers implemented/supported those features. So it was pain to use old JS syntax just for the sake for supporting the old browsers. So around same time, babel was released aiming to convert modern js into es5 syntax. Babel was integrated with webpack using babel-loader. Babel also supports ES6 modules / ESM
JS ecosystem consists of below things.
  • JS runtime environments like NodeJS, Deno or Bun
  • JS frameworks like react, angular JS, vue
  • package managers - npm or yarn - npm registry
  • type safety using typescript(Microsoft) or flow(Facebook)
  • Transpilers and polyfills like babel - Convert modern JS code into ES5 syntax
  • module bundlers - e.g. webpack, parcel, rollup, vitejs
  • Linters and formatters - ESLint, Prettier
  • Testing frameworks - Jest, Cypress
  • GraphQL and Apollo
  • Static site generators - NextJS, GatsbyJS, NuxtJs
  • Mobile applications - React Native
  • Desktop apps - electron

Babel

Babel converts modern JS into ES5 or other older JS syntax. Below command will install Babel in current project.

npm i @babel/core @babel/preset-env @babel/cli -D
Babel config can be put in .babelrc.json file. In below example, we are asking babel to convert ES6 arrow function syntax.

const arrowFunc = () => console.log("This is ES6 feature")
To convert above code into ES5, you can use below command. But before that make sure you install arrow function plugin - @babel/plugin-transform-arrow-functions

  "plugins": ["@babel/plugin-transform-arrow-functions"]
  
But above approach is not scalable. If you want to convert all ES6 syntax, it is better to use preset - "@babel/preset-env"

npx babel source.js --out-file destination.js
# or you can use below command
yarn babel source.js --presets "@babel/preset-env" 
As you can see in above command, we are converting the index.js to old syntax using babel command. Please note the use of presets. With preset set to "@babel/preset-env", we are telling babel to convert the JS code in such a way that all new JS features are converted to old JS syntax so that all old browsers will be able to execute the code without any issues. preset-env refers browserslist, compat-table, and electron-to-chromium when transpiling the code. There are lot of other presets that can be used based on your project needs.
  • @babel/preset-flow
  • @babel/preset-react
  • @babel/preset-typescript

But the problem with above solution is that final js file will be huge. To avoid this, we can use .browserlistrc file to specify what browsers should be supported.


not ie all - do not support IE
>0.25% - browsers with market share of .25% or more

Polyfill

Babel converts the new syntax to old syntax but it can not implement the new features like promises, symbols, collections, iterators, typed arrays etc. To support these features in old browsers, we must use polyfill. Polyfill is nothing but module that implements new ES6 features using old ES5 syntax. core-js is the most popular polyfill used in web app projects.

You can easily integrate this polyfill with Babel

First install the core js.

npm i core-js
Then integrate it with Babel using config file - .babelrc.json

 {
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "entry",
        "corejs": 3
      }
    ]
  ]
}
Polyfills will be added based on which browsers we want to support.

Webpack

here are reasons why you should use webpack.
  • No need to maintain the order of script tags in html page
  • Avoid pollution of global scope
  • "npx webpack" will start reading src/index.js and then build dependency graph. Finally a bundle will be created in dist/main.js which can be used to embed in html pages
  • supports Common JS as well ES6 modules
  • We can extend functionality using plugins and loaders (e.g. babel-loader, ts-loader, css-loader)
  • bundle js, css, html, images etc e.g. If index.js imports lodash, it will be bundled with index.js in a single file
  • Supports tree shaking
  • Supports lazy loading
  • async chunk loading
  • pre fetching
  • hot module replacement
Here is the list of important packages that you will need to install for react project.
  • npm install webpack-cli webpack webpack-dev-server webpack-cli -D
  • npm install react react-dom prop-types react-router-dom semantic-ui-react
  • npm install @babel/core @babel/preset-env @babel/preset-react babel-loader css-loader style-loader html-webpack-plugin -D
Here is sample webpack.config.js file.

module.exports = {
		entry: './src/index.js',

		output: {
			path: path.resolve( __dirname, 'build' ),
			filename: 'dest.js',
		},


		module: {
			rules: [
				{
					test: /.jsx$|.es6$|.js$/,
					use: {
						loader: 'babel-loader',
						options: {
							presets: ['react'],
						}
					},
					exclude: /(node_modules|bower_components)/
				}
      ]
    }
  }
Some important config options in webpack.config.js are
  • entry - location of index file of the app (default is src/index.js)
  • output - location of final bundle file. (default is dist/main.js)
  • mode - It can be development or production
  • module rules for js (process js files using babel-loader) and css files (Process css files using style-loader and css-loader).
  • plugins - HtmlWebpackPlugin - inject bundle into index.html
  • devServer - host and port on which webpack server will serve the app. (default is localhost:3000) To serve the pages via webpack server, use command "npx webpack serve"
  • devtool - creates source map (e.g. 'inline-source-map')
  • optimization
Then run webpack command.

npx webpack --config webpack.config.js --mode=development

Config files

  • package.json
  • package.lock.json
  • jsconfig.json
  • tsconfig.json - "allowSyntheticDefaultImports": true means allow ES6 default imports even when source code does not export anything as default. This is the case with react. We may have to use
  • .babelrc.* or babel.config.*
  • webpack.config.js

Resources

  • https://youtu.be/QliwSwWHJoQ - webpack adoption
  • https://www.youtube.com/watch?v=qJWALEoGge4 - module evolution
  • https://youtu.be/h3LpsM42s5o - react app from scratch

Web development and Automation testing

solutions delivered!!