Front-end evolution diagram:


Images from Dinosaur Comics by Ryan North

Sometimes it’s hard to learn modern JavaScript development without getting started. Ecosystems are changing so fast that it’s hard to understand what problems different tools are trying to solve. I’ve been programming since 1988, but it wasn’t until 2014 that I started learning JavaScript in earnest. Remember when I first encountered Browserify and saw its tagline:

Browserify lets you require(‘modules’) in the browser by bundling up all of your dependencies.

I don’t understand any of the words in this sentence and don’t know why this is useful to me as a developer.

The goal of this article is to provide a historical perspective on the evolution of JavaScript tools and see how they evolved step by step to where they are today in 2017. In the beginning, we will build a website like the original dinosaur family — using simple HTML and JavaScript without any tools. Then introduce the different tools step by step to see what problem each solves. Come on ~

The “old school” approach to JavaScript

First, build a website using HTML and JavaScript like “old school” – manually download and inline files. Like this ~

<! -- index.html --> <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JavaScript Example</title> <script src="index.js"></script> </head> <body> <h1>Hello from HTML! </h1> </body> </html>Copy the code

this line refers to a separate file called index.js introduced in the same directory:

// index.js console.log("Hello from JavaScript!" );Copy the code

That’s almost all you need to build your site. Now, you want to add a library written by someone else, such as moment.js (a library that formats dates in a more readable way). For example, you could use a moment function like this:

moment().startOf('day').fromNow(); // 20 hours ago

Copy the code

But that’s assuming you’ve included moment.js on your site! On the moment.js home page, you can see the following guide:

Hmm, there seems to be a lot of stuff on the right side of Install! Ignore it for a moment — we can download the moment.min.js file into the parent directory and introduce it in index.html:

<! -- index.html --> <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Example</title> <link rel="stylesheet" href="index.css"> <script src="moment.min.js"></script> <script src="index.js"></script> </head> <body> <h1>Hello from HTML! </h1> </body> </html>Copy the code

Note that moment.min.js will download before index.js, so you can use the moment function in index.js like this:

// index.js console.log("Hello from JavaScript!" ); console.log(moment().startOf('day').fromNow());Copy the code

This is how we use JavaScript libraries to build websites! The advantage of this approach is that it is very easy to understand. The downside, however, is that when the library author updates, finding and downloading a new version every time becomes annoying.

Using JavaScript Package Management Tool (NPM)

Since about 2010, several competing JavaScript package management tools have emerged to automate the download and upgrade process from a central repository. Bower was arguably the most popular in 2013, but was eventually beaten by NPM around 2015. (It’s worth noting that YARN began to take its place as an alternative to NPM around 2016, but NPM still prevailed.)

Note that NPM, as a package management tool, was originally designed specifically for Node.js, a JavaScript runtime that runs on the server side, not the front end. So it might seem an odd choice as a front-end package management tool for running JavaScript in a browser.

Note:Using package management tools usually involves using the command line, which was not a required skill for a front-end developer in the past. If you’ve never used it, read it
This tutorialGive an overview. However, knowing how to use the command line is part of modern JavaScript development (and an important step into other areas).

Let’s see how NPM can be used to automatically install moment.js. If you have Node.js installed and NPM installed with it, you can navigate your command line into the index.html directory and type:

$ npm init 

Copy the code

This will lead you to fill in a few questions (default values are fine, you can always press “Enter”) and generate a file called package.json that looks something like this:

{" name ":" your project -- the name ", "version" : "1.0.0", "description" : ""," main ":" index. Js ", "scripts" : {" test ": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }Copy the code

To install the monment.js package, we can follow the NPM installation instructions on the home page by typing:

$ npm install moment --save

Copy the code

This command does two things — first, it downloads all the code from the moment.js package into a folder called node_modules. Second, it automatically modiizes the package.json file to track moment.js as a dependency for the project:

{" name ", "modern javascript - example", "version" : "1.0.0", "description" : ""," main ":" index. Js ", "scripts" : {" test ": "Echo \"Error: no test specified\" && exit 1"}, "author": "", "license": "ISC", "dependencies": {// "^ 2.19.1}}"Copy the code

This is very useful when sharing projects with others — instead of sharing the node_modules folder directly (which can be very large), you just share your package.json file and other developers can use the command NPM install to automatically install the required packages for the project.

Now, instead of manually downloading moment.js from the website, we can download and update it automatically using NPM. Then look inside node_modules and notice that the moment.min.js file is located in node_modules/moment/min. So you can import the NPM download version of moment.min.js into the index.html file like this:

<! -- index.html --> <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JavaScript Example</title> <! Manual bold - the next line - > < script SRC = "node_modules/moment/min/moment. Min. Js" > < / script > < script SRC = "index. Js" > < / script > < / head > <body> <h1>Hello from HTML! </h1> </body> </html>Copy the code

So the good news is that we can now download and update packages using NPM from the command line. The bad news is that we still have to search the entire node_modules directory to locate each package and manually add it to our HTML files. So next, let’s see how we can automate the process as well.

Using the JavaScript Module Packaging tool (Webpack)

Most programming languages provide a mechanism for importing code from one file into another. JavaScript, however, was originally designed without this feature, because JavaScript was designed to run in the browser and did not have access to the computer client’s file system (for security reasons). So for a long time, JavaScript code to organize multiple files was to download each file, and variables were shared globally.

This is actually exactly what we did with moment.js — download the entire moment.min.js file into HTML, define a global variable called moment, It is available for all files downloaded after moment.min.js (whether or not you really need it).

In 2009, a project called CommonJS sprang up with the goal of standardizing the JavaScript ecosystem outside of the browser. A big part of CommonJS is the specification of a modular system that allows JavaScript to import and export code without resorting to global variables, as most programming languages do. The best-known implementation of the CommonJS module specification is Node.js. (Note: Node is not implemented exactly as a specification, but rather as a modification of the module specification and a few additional features.)

As mentioned earlier, Node.js is a server-side runtime designed for JavaScript. If we were to rewrite the previous example using the Node.js module, instead of downloading the entire monment.min.js file with HTML tags, you could load it directly from a JavaScript file like this:

// index.js var moment = require('moment'); console.log("Hello from JavaScript!" ); console.log(moment().startOf('day').fromNow());Copy the code

However, this is the module-loading method that only works in Node.js, which works fine as a server-side language with access to the computer’s file system. Node. Js also know every path of NPM module, so we don’t need to write the require (“. / node_modules/moment/min/moment. Min. Js), and can directly write the require (‘ moment ‘) – whether very close ~

This is all great for Node.js, but if you actually run the above code in a browser, you’ll get an error require is not defined ‘. Browsers don’t have permissions on the file system, which means that loading modules this way is tricky — files must be loaded dynamically, synchronously (slowing down execution) or asynchronously (not in chronological order).

This is where the module packer comes in. The JavaScript module wrapper is a tool that can bypass this problem during the code build process (with file system permissions) and package to produce a browser-compatible production version (without file system permissions). In this example, we need a module packer that finds all of the REQUIRE statements (which are illegal in browser-side JavaScript) and replaces them with the actual contents of the required file. The end result is a packaged JavaScript file (without the require statement)!

Once the most popular module packer was Browserify, released in 2011, which advocated the use of node.js-style require statements on the front end (which was crucial for NPM to become the front-end package management tool of choice). Around 2015, WebPack finally became a more widely used package manager (a process that was greatly facilitated by the popularity of React, which took full advantage of webPack’s various features).

See how webpack can make the above require(‘moment’) example work in a browser. First, we need to install webPack into the project. Webpack itself is also an NPM package, so you can happily install it using the command line:

$ npm install webpack --save-dev

Copy the code

Note that the –save-dev parameter — makes it a dependency for the development environment, not the production environment, since it doesn’t need to be put on the server. You can see the corresponding changes in the package.json file, which have been automatically updated as follows:

{" name ", "modern javascript - example", "version" : "1.0.0", "description" : ""," main ":" index. Js ", "scripts" : {" test ": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "moment": "^ 2.19.1"}, "devDependencies" : {/ / manual bold "webpack" : "^ 3.7.1"}}Copy the code

Now that webpack is installed as a package in node_modules, you can use webpack from the command line like this:

$ ./node_modules/.bin/webpack index.js bundle.js  

Copy the code

This command will run the webpack tool in node_modules, which will start with index.js, find all the require statements, replace them with the appropriate code, and output a single file called bundle.js. This means we no longer need index.js in the browser because it contains the illegal require statement. Instead, use the output bundle.js file, so we should modify the index.html file:

<! -- index.html --> <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JavaScript Example</title> <! <script SRC ="bundle.js"></script> </head> <body> <h1>Hello from HTML! </h1> </body> </html>Copy the code

Refresh your browser and everything works as usual again.

Notice that every time we modify index.js we run a long list of webpack commands. Annoying, and even more so when we use webPack’s more advanced features (such as using generating source maps to debug the original code from the compiled code). Webpack can read the corresponding Settings from a configuration file called webpack.config.js in the root directory of the project file, which in our case should look something like this:

// webpack.config.js
module.exports = {
 entry: './index.js',
 output: {
   filename: 'bundle.js'
 }
};

Copy the code

This way, every time we change index.js, we can run it on the command line:

$ ./node_modules/.bin/webpack 

Copy the code

We don’t need to point out the index.js and bundle.js options anymore because webpack is already loaded from webpack.config.js. That’s a little better, but it’s still annoying to have to type commands every time you change code — we’ll make this process a little smoother later

When you look at it, while it may not seem like much has changed, the process has actually made a lot of progress. We no longer need to load global variables with extra tags. Any new JavaScript library can be introduced in a JavaScript file using the require statement, rather than adding a

Use new language features and compile code (Babel)

Transpiling means converting code from one language to another similar language. This is an important part of front-end development – browsers are slow to add new features, and new languages with experimental features are created and compiled to work in browsers.

For CSS, Sass, Less, Stylus, to name a few. For JavaScript, the most popular was CoffeeScript (circa 2010), while most people now use Babel or TypeScript. CoffeeScript focuses on changing the language style of JavaScript — optional parentheses, prominent whitespace, and so on. Babel is not a new language but a compiler that compiles new features in the next generation of JavaScript(ES6 and later) that are not yet implemented in all browsers into older, more compatible JavaScript(ES5). TypeScript is a language identical to the next generation of JavaScript, but with optional static typing. Many people choose Babel because it is closer to normal JavaScript.

Take a look at an example of how to use Babel in the steps we just used to build with WebPack. First use the command line to install Babel (NPM package) into the project:

$ npm install babel-core babel-preset-env babel-loader --save-dev 

Copy the code

Note that we installed three separate packages as development dependencies — babel-core is the main part of Babel, and babel-preset-env is a new feature that predefines which JavaScript to compile, Babel-loader is a package that enables Bebel and WebPack to work well together. We can configure webpack to use babel-loader:

// webpack.config.js module.exports = { entry: './index.js', output: { filename: 'bundle.js' }, module: { rules: [// manual padding {test: /\.js$/, exclude: /node_modules/, use: {loader: 'babel-loader', options: {presets: ['env'] } } } ] } };Copy the code

The syntax can seem confusing (fortunately, you don’t need to edit it often). Basically we are telling Webpack to look for any.js ending files (except for the node_modules directory) and use babel-loader to load and compile JavaScript files with babel-preset-env as Settings. You can see more information about webPack configuration here.

Now that we have everything in place, we can write the ES2015 feature in JavaScript. Here is a simple example of an ES2015 template string in index.js:

// index.js var moment = require('moment'); console.log("Hello from JavaScript!" ); console.log(moment().startOf('day').fromNow()); var name = "Bob", time = "today"; console.log(`Hello ${name}, how are you ${time}? `);Copy the code

We can also use ES2015 import statements instead of require loading modules, as in many code libraries today:

// index.js import moment from 'moment'; console.log("Hello from JavaScript!" ); console.log(moment().startOf('day').fromNow()); var name = "Bob", time = "today"; console.log(`Hello ${name}, how are you ${time}? `);Copy the code

In this case, the import syntax is not particularly different from require, but import has more flexibility in more advanced cases. Due to the changes to index.js, we need to re-run webpack from the command line:

$ ./node_modules/.bin/webpack 

Copy the code

Now you can refresh index.html in your browser. At the time of writing, most modern browsers support all ES2015 features, so it’s sometimes hard to tell if Babel is doing what it’s supposed to be doing. You can test it in some older browsers like IE9, or you can look at bundle.js to find the compiled code:

// bundle.js // ... console.log('Hello ' + name + ', how are you ' + time + '? '); / /...Copy the code

Here you can see that Babel has compiled ES2015 template strings into regular JavaScript string concatenation to maintain browser compatibility. Although this particular example isn’t very exciting, being able to compile code is a powerful thing. JavaScript is coming with some exciting language features like async/await and you can start writing better code now. Although compilation can sometimes seem tedious and painful, it has driven a lot of exciting improvements in languages over the past few years, as people are able to test tomorrow’s features today.

We’re almost done, but there are still some rough parts in the workflow. If we are concerned about performance, we should minimize packaging files, and the process should be concise because we have merged files during the build process. And we still need to re-run the webpack command every time we modify the JavaScript file. So the next step is to find some handy tools to solve these problems.

Using automated build tools (NPM scripts)

Now that the build process is used for JavaScript modular development, task management tools should also be useful to automate the different build processes. For front-end development, these tasks include minimizing code files, optimizing images, running tests, and so on.

Grunt was the most popular front-end build tool in 2013, with Gulp not long after. Both rely on plug-ins that integrate other command-line tools. The most popular option these days seems to be to use NPM’s built-in scripting capabilities themselves, instead of plug-ins, directly using other command-line tools.

Let’s write an NPM script to make WebPack easier to use. Simply modify package.json as follows:

{" name ", "modern javascript - example", "version" : "1.0.0", "description" : ""," main ":" index. Js ", "scripts" : Error: no test specified\" && exit 1", "build": "webpack -- progress-p ", "watch": "webpack --progress --watch" }, "author": "", "license": "ISC", "dependencies": { "moment": "^ 2.19.1"}, "devDependencies" : {" Babel - core ":" ^ 6.26.0 ", "Babel - loader" : "^ 7.1.2", "Babel - preset - env" : "^1.6.1", "webpack": "^3.7.1"}}Copy the code

Here we have added two new scripts, build and Watch. To run the build task, type:

$ npm run build

Copy the code

This will run Webpack (using the configuration in webpack.config.js we wrote earlier) and show the process with the –progress option, while the -p option minimizes production code. Execute the watch script:

$ npm run watch

Copy the code

It is convenient for developers to use the –watch option to automatically re-run the Webpack command after each change to the JavaScript file.

Note that the script in package.json doesn’t have to specify the full path to webpack./node_modules/.bin/webpack ‘, since Node.js knows the location of every NPM package. We could even install Webpack-dev-server, a simple Web server with hot updates, to make development even better. To install it as a development dependency, just:

$ npm install we         bpack-dev-server --save-dev 

Copy the code

Then add a line of script to package.json:

{" name ", "modern javascript - example", "version" : "1.0.0", "description" : ""," main ":" index. Js ", "scripts" : {" test ": "echo \"Error: no test specified\" && exit 1", "build": "webpack --progress -p", "watch": "Webpack --progress --watch", "server": "webpack-dev-server --open", "author": "", "license": "ISC", "dependencies" : {" moment ":" ^ 2.19.1 "}, "devDependencies" : {" Babel - core ":" ^ 6.26.0 ", "Babel - loader" : "^ 7.1.2," "Babel - preset - env" : "^ 1.6.1", "webpack" : "^ 3.7.1"}}Copy the code

Now you can run dev Server from the command line:

$ npm run server

Copy the code

This will open your index.html page at localhost:8080 (the default) in your browser. As soon as you change the code in index.js, Webpack-dev-server repackages the JavaScript and automatically refreshes the browser. This is a real time saver and allows you to focus on the code itself rather than constantly switching back and forth between the browser and the code to see changes.

The above just scratches the surface, there are quite a few options for both Webpack and Webpack-dev-server (you can read more here). You can also write NPM scripts to run other tasks, such as converting Sass to CSS, compressing images, running tests, and so on. NPM scripts themselves are full of advanced options and tricks — This talk by Kate Hudson is a great start.

conclusion

This is plain modern JavaScript. We’ve gone from simple HTML and JS to automatic downloading of third-party packages using package management tools, generating individual files using module packers, leveraging compilation tools to use future JavaScript features, and using task build tools to automate different parts of the code build process. There is no doubt that it has changed a lot, especially for beginners. Web development used to be a great starting point for new programmers because it was so easy to get up and running. The ever-changing tools of today are daunting.

It’s still not as bad as it looks. Things are starting to settle down, especially as the front-end fits into the Node ecosystem in a viable way. Using NPM as a package management tool makes the front and back ends more unified, Node require or import statements can be modular development, and NPM scripts automatically run tasks. This greatly simplifies the workflow compared to a year or two ago!

Even better for beginners or experienced developers, many frameworks today come with tools that make it easier to initialize projects. Ember has ember-cli, a great influence on Angular angular-cli. React create-react-app, Vue – CLI, etc. These tools will have almost everything you need ready — all you need to do is start writing code. These tools are not magic, however, they just keep everything together and up to date – you may often need to do some extra configuration for your Webpack, Babel, etc. So it’s still crucial to understand what each piece does, as we’ve covered in this article.

Modern JavaScript can be really frustrating at times because of the speed of change and evolution. Although it sometimes seems like we’re reinventing the wheel, the rapid evolution of JavaScript is driving innovation, such as hot updates, real-time linting, and time-travel debugging. As a developer, it’s exciting. Hopefully this information will be useful on your journey

Special Thanks to @Ryanqnorth’s Dinosaur Comics.


The original address


Old iron people pay attention to “Big Talk WEB Development” wechat public number, recommend WEB development related technology blog posts from time to time, mutual encouragement and learning exchanges! Qr code left


Left left left left down down downClick to get taobao coupon, the recommended commission reward will be used for the server cost of this site, there is a need to buy friends can get vouchers, thank you for your support!