Writing JavaScript on modern Web

Writing JavaScript on modern Web

·

4 min read

As JavaScript continues to evolve, we want to use the latest JavaScript syntax and features on the one hand, and we want to make that code still work in older browsers on the other. To achieve both goals, we need to use a number of tools, typically Babel and webpack. Let's try to use them below.

Babel first

Babel is a tool to let us write JavaScript with latest syntaxes and features, but still can be run in older browsers. This is done by transpiling. We tell Babel our needs which is what browsers we want to support and give it our source code, then Babel will transpile our source code into destination code which will meet our needs.

Let's see how this can be done.

First, set up our project with following command.

$ mkdir babel-ex
$ cd babel-ex
$ npm init -y

$ npm install @babel/core @babel/cli @babel/preset-env --save-dev
$ npm install core-js@3 --save

Here, we install four packages:

  • @babel/core: Babel engine
  • @babel/cli: Babel cli
  • @babel/preset-env: A smart preset that contains all basic transformations
  • core-js@3: This is the polyfill we need for new JavaScript features

Note that core-js@3 should be bundle into production code later, so we use option --save to install it as a dependency.

Then, let's write some JavaScript with modern syntax, src/index.js:

const x = 5;
console.log({ x });

let y;
console.log({ y });

const sampleFunction = () => "this is a return value";
console.log(sampleFunction());

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
}
console.log(new Person("yao", 30));

const hasThree = [1, 2, 3].includes(3);
console.log(hasThree);

y ||= "a new value";
console.log({ y });

Then we create Babel config file babel.config.json to tell Babel what we want.

{
    "presets": [
        [
            "@babel/preset-env",
            {
                "targets": {
                    "chrome": "58",
                    "ie": "11"
                },
                "useBuiltIns": "usage",
                "corejs": "3"
            }
        ]
    ]
}

You can see a few things in the config file:

  • We want to use @babel/preset-env
  • Targets is to support chrome which version above 58 and ie 11 browser
  • We want to use corejs version 3 to polyfill our code
  • "useBuiltIns": "usage" stands for only polyfill the new features we used in code

Now let's config a script command for babel in package.json file.

{
    "scripts": {
        "babel": "babel src/index.js --out-file babel-out/script-production.js"
    }
}

Then we run command npm run babel, we should get our output file. Let's see how the transformation is done.

"use strict";

require("core-js/modules/es.function.name.js");

require("core-js/modules/es.array.includes.js");

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var x = 5;
console.log({
  x: x
});
var y;
console.log({
  y: y
});

var sampleFunction = function sampleFunction() {
  return "this is a return value";
};

console.log(sampleFunction());

var Person = function Person(name, age) {
  _classCallCheck(this, Person);

  this.name = name;
  this.age = age;
};

console.log(new Person("yao", 30));
var hasThree = [1, 2, 3].includes(3);
console.log(hasThree);
y || (y = "a new value");
console.log({
  y: y
});

Good, we can see that all new syntax is transformed and new features is polyfilled as expected.

webpack to bundle

Now we successfully transform our source code, but it cannot run because of the polyfill require code cannot run in browser. We need webpack to bundle our code. Let's see how.

First, we need to install some packages.

$ npm install webpack webpack-cli babel-loader html-webpack-plugin --save-dev
  • webpack: webpack engine
  • webpack-cli: webpack cli
  • babel-loader: to load babel in webpack
  • html-webpack-plugin: to output a html

Then is the webpack config file webpack.config.js:

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
    entry: "./src/index.js",
    output: {
        path: path.resolve(__dirname, "webpack-out"),
        filename: "script.production.js",
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: "babel-loader",
                },
            },
        ],
    },
    plugins: [new HtmlWebpackPlugin()],
    mode: "production",
};

The process is simple: we set up entry and output, specify we want use babel for js files and use HtmlWebpackPlugin.

Let's add a script command for webpack. Below is the final package.json file.

{
    "name": "babel-ex",
    "version": "1.0.0",
    "scripts": {
        "babel": "babel src/index.js --out-file babel-out/script-production.js",
        "webpack": "webpack"
    },
    "devDependencies": {
        "@babel/cli": "^7.15.7",
        "@babel/core": "^7.15.8",
        "@babel/preset-env": "^7.15.8",
        "babel-loader": "^8.2.2",
        "html-webpack-plugin": "^5.3.2",
        "webpack": "^5.57.1",
        "webpack-cli": "^4.9.0"
    },
    "dependencies": {
        "core-js": "^3.18.2"
    }
}

Let's bundle our code.

$ npm run webpack

> babel-ex@1.0.0 webpack /Users/yao/code/js/babel-ex
> webpack

asset script.production.js 11.8 KiB [compared for emit] [minimized] (name: main)
asset index.html 227 bytes [compared for emit]
runtime modules 884 bytes 4 modules
modules by path ./node_modules/core-js/internals/*.js 32.1 KiB 62 modules
modules by path ./node_modules/core-js/modules/*.js 1.27 KiB
  ./node_modules/core-js/modules/es.function.name.js 739 bytes [built] [code generated]
  ./node_modules/core-js/modules/es.array.includes.js 559 bytes [built] [code generated]
./src/index.js 703 bytes [built] [code generated]
webpack 5.57.1 compiled successfully in 1143 ms

Finally, we should see the webpack-out/index.html and webpack-out/script.production.js file.

Run the html file in the browser, we should see the code executed properly in the console.

136306937-225249b4-56eb-4b4b-b34c-c920a9bb224e.png