preface

Modularity idea

What is modular thinking?

The idea of modularity is to break up a piece of code according to a specific function. Each piece of code has its own purpose. It can be designed, developed, tested independently, and finally put together through interfaces.

The disadvantages of introducing script tags into a page in the traditional way are:

  • You need to manually maintain the loading order of the JavaScript. When thesescriptWhen a dependency relationship exists, you need to manually adjust the sequence to prevent dependency problems.
  • multiplescriptRequests are also many, meaning every onescriptTags all request static resources once, and too many requests can slow down the performance of a web page.
  • eachscriptAll top-level scopes are global scopes, and if left unchecked, global scope contamination will occur.

Modularity will solve these problems:

  • By importing and exporting statements, we know the dependencies between modules
  • With the help of packaging tools, we can merge and compress some resources to reduce network overhead
  • Multiple modules are scoped separately and name conflicts do not occur

Modular ideas: AMD, CommonJS, CMD, ES Module and so on

Modularize the process of change

Use functions for encapsulation

We can encapsulate different logic and functions into different global functions so that the logic can be decoupled

Writing:

Const base = 10 function add(a, b) {return a + b + base} Function multiply(a, b) {return a*b*base}Copy the code

Above is the simplest example, respectively implement the method of addition, subtraction and multiplication, and add a cardinality, later extension and reuse can be combined by themselves.

Disadvantages: Global variable pollution, easy to cause naming conflicts, and ambiguous relationships

Use the form of a namespace

We generally use A.B.C.D to find the corresponding value layer by layer. We can use simple objects to encapsulate our logic, so as to reduce global variables, thus reducing variable pollution and naming conflicts.

Writing:

let convertFun = {
    base: 10,
    add: function(a, b) {
        return a + b + this.base
    },
    subtract: function(a, b) {
        return a - b - this.base
    },
    multiply: function(a, b) {
        return a*b* this.base
    }
}
Copy the code

As you can see above, we have wrapped the previous four conversion methods in an object, which is equivalent to an extra layer of namespace. To access them, we need to use convertfun.add (1,2), which is isolated from global variables.

Disadvantages: Internal methods and state can be arbitrarily modified by external, such as external arbitrarily modified base

Self-executing function

From the above point of view, we just need to solve the problem of privatization variables can be considered a good module.

In order not to affect the global scope, we can use the self-executing function to do the isolation, because it is executed at compile time, it is released after execution, it does not affect other global variables, it is just like a window, so how can we define variables in the same way that we define global variables? The answer is to use closures, where variables outside the function can be accessed inside the function, so the closure is not immediately recycled.

Usage:

(function(window) {let base = 10 function add(a, b) {return a + b + base} C) {multiply(a, b) {multiply(a, b) {multiply(a, b) {return a*b*base} multiply } })(window)Copy the code

So the outside world can’t change to base, so base becomes a private property. See the above writing, can not help but think of jQuery, is also used in this way, the source code is as follows:

(function(window) {var jQuery = (function() {// return jQuery})(); / /... window.jQuery = window.$ = jQuery })(window)Copy the code

However, there is a problem with this method, that is the dependency problem, when the module depends on another module, then need to add a new parameter to solve, so you can use the following form to pass in the dependency.

(function(window, jQuery) { let base = 10 function add(a, b) { // jQuery..... // subtract function subtract(a, b) {// jQuery..... Function multiply(a, b) {// jQuery..... Return a*b*base} // Mount window.convertFun = {add, subtract, multiply}})Copy the code

This is the evolution of modularity, but when we have multiple such script files introduced into one, it can lead to too many requests, unclear dependencies, and load order problems. To solve these problems, we also need to resort to some modularity ideas, namely modularity specifications.

Why Webpack

  • Support for multiple module standards by default, including AMD,CommonJS, and ES6 modules.
  • Webpack has a complete code splitting solution. Only necessary parts are loaded on the first screen, and less important functions are dynamically loaded at the end of the first screen, effectively improving the loading speed of the first screen.
  • Webpack handles various types of resources.
  • Has a huge community of support. In addition to the core library, there are many peripheral plug-ins and tools.

Installation and startup

The installation

To use WebPack first, you must install WebPack.

We can use NPM init-y to quickly initialize a project

Then use NPM install [email protected] –save-dev. Here we installed 4.29.4. Each version may be different. So the installation is divided into global installation and local installation, we use local installation save-dev, does not affect your global version.

In addition to installing Webpack, we also need to install the webpack command line tool webpack-cl, so we use NPM install [email protected], also to pay attention to the same version.

If the installation is successful, we can use NPX webpack -v and NPX webpack-cli -v to check whether the installation is successful.

Here is the whole process:

// Initialize the project
npm init -y
// Install the WebPack core module
npm install webpack@4.294. --save-dev
// Install the Webpack command-line tool
npm install webpack-cli@3.23. --save-dev
// Verify that the installation is successful
npx webpack -v
npx webpack-cli -v
Copy the code

Start the

So let’s package our first application.

  • Initialize the file directory first:

    First, we will create a new test1 folder to represent test1, and then we will create a separate folder to do the test.

    Create an index. HTML file and a SRC folder in test1, add an index.js file in SRC, and add an add.js file in utils

  • Write code:

    We’ll write an add method in test1/ SRC /utils/add.js

    export default function(a, b) {
        return a + b
    }
    Copy the code

    Then write it outside in test1/ SRC /index.js

    import add from "./utils/add";
    
    document.write(Question: What is 1+2? 1 + 2 = '+ add(1.2))
    Copy the code

    Finally, in the test1/index.html template we’ll introduce a bundle.js package that we assume will be packaged into the root dist by default, so we’ll put bundle.js under test1 in dist

    <! DOCTYPEhtml>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
        <title>Document</title>
    </head>
    <body>
        <script src=".. /dist/test1/bundle.js"></script>
    </body>
    </html>
    Copy the code
  • Execute the package command:

    The packaging command starts with webpack, and there are many configurations, so for now we only need to worry about the most basic input and output configurations, namely –entry and –output

    npx webpack --entry=./test1/src/index.js --output-filename=./test1/bundle.js --mode=development

The following command output is displayed:

Following the steps above, you’ll eventually see an additional dist in the root directory, and in dist there will be test1, which will contain bundle.js, which is our packaged file.

We usually use NPM run build instead of this long command, so we can add this to the scripts object in package.json

"scripts": {
    "build": "webpack --entry=./test1/src/index.js --output-filename=./test1/bundle.js --mode=development"
}
Copy the code

It’s the same when you pack it up at the end

We can also simplify by just executing the webpack command. When executing the webpack command, we will look for the webpack.config.js configuration file, which we usually put in the root directory, and change the configuration mode of the command line to key-value.

// packages.json
"scripts": {
    "build": "webpack" / / simplified
}
Copy the code
// webpack.config.js
var path = require('path')

module.exports = {
    entry: './test1/src/index.js'.output: {
        path: path.join(__dirname , '/dist'),// The absolute path is required
        filename: './test1/bundle.js',},mode: 'development'
}
Copy the code

Now that we have the webPack capability enabled, this is a very basic introduction, and more packaging methods will be covered later.

If we want to make it easier to develop locally, we can use the convenient local development tool Webpack-dev-server, which means that a service is locally picked up, repackaged, and then implemented (module hot replacement) when saved. It is only used in a development environment, so you can install it using the following command,

npm install webpack-dev-server --save-dev
Copy the code

In a production environment, we don’t need it, so it’s appropriate to put it in devDependencies. If we install dependencies when the project goes live, we can use NPM install — Production to filter out redundant modules in devDependencies for quick installation and release.

Let’s use this tool:

Let’s start by adding the dev command to package.json so that we can start it when we run NPM run dev.

// package.json
{
  "scripts": {
    "build": "webpack"
    "dev": "webpack-dev-server"}}Copy the code

Then we need to configure devServer in webpack.config.js:

// webpack.config.js
var path = require('path')
const htmlPlugin = require('html-webpack-plugin')

module.exports = {
    entry: './test1/src/index.js'.output: {
        path: path.join(__dirname , '/dist'),// The absolute path is required
        filename: './test1/bundle.js',},plugins: [new htmlPlugin({ title: 'test'})].mode: 'development'.devServer: {
        publicPath: '/'.port: 3000}}Copy the code

We also need NPM to install the html-webpack-plugin –save-dev, which automatically generates index.html in the dist folder and automatically imports the packaged JS. By accessing localhost:3000, you can access the packaged content.

Webpack-dev-server can be thought of as a server, or server, whose main job is to receive browser requests and return resources. When NPM run dev starts the service, it then packs the modules and bundles the resource, bundle.js, which verifies the URL address when it receives the request. If the address is the configured resource service address publicPath, the webPack result returns the resource to the browser. If the URL address does not belong to the resource service address, it is displayed by reading the source file on the hard disk.

So webpack-dev-server does two things:

  • The module is packaged and the resource request for the packaged result is processed
  • Web services that process static resource requests and return them to the client

So some tutorials have publicPath set to /dist, and if we go to localhost:3000, we get something like this:

Because the URL does not match the publicPath resource address, we return the disk resource. If we want to see the result of packing, we can go to localhost:3000/dist. Localhost :3000 = /; localhost:3000 = /;

Note the difference between Webpack development and webpack-dev-server development. Webpack development packages generate new bundle.js each time, while webpack-dev-server just puts the package results in memory. The actual bundle.js is not generated, and the in-memory packaging results are returned to the browser every time a request is received, so we remove the dist directory and if it doesn’t exist, it’s still accessible. This was also because we changed the directory and filename frequently during development, and if we packaged those changes into DIST each time, we would generate a lot of junk files. In addition, it can automatically refresh live-reloading to improve local development efficiency.

At this point, we are familiar with webPack installation and packaging, and we will learn more about packaging configuration and principles later.