It is mainly used for learning Webpack, the original address is github.com/ruanyf/webp…

Installation Guide

First, install Webpack and webpack-dev-server globally

$ npm i -g webpack webpack-dev-server
Copy the code

Then clone ruan Yifeng’s warehouse

$ git clone https://github.com/ruanyf/webpack-demos.git
Copy the code

Install dependencies

$ cd webpack-demos
$ npm install
Copy the code

Now go into the demo* directory and run them

$ cd demo01
$ npm run dev
Copy the code

The above code does not automatically open your browser, you need to manually visit http://127.0.0.1:8080

Preface: What is Webpack

Webpack is a front-end tool for building Javascript module scripts for use by browsers. It’s similar to Browserify, but can do a lot more

$ browserify main.js > bundle.js
# the above and below codes have the same effect
$ webpack main.js bundle.js
Copy the code

Webpack requires a configuration file called webpack.config.js, which is a CommonJS module.

Module.exports = {entry: // webpack.config.js contents module.exports = {entry:'./main.js',
  output: {
    filename: 'bundle.js'}};Copy the code

When webpack.config.js is built, webpack can be run without arguments

$ webpack
Copy the code

There are some must-know parameter options below

  • webpack— Build commands at development time
  • webpack -pBuild commands when releasing the product
  • webpack --watch— Builds for incremental development
  • webpack -d— Including Source Maps
  • webpack --colorsMake the build output look better

You can customize the scripts option in webpack.config.js, as shown below

// package.json
{
  // ...
  "scripts": {
    "dev": "webpack-dev-server --devtool eval --progress --colors"."deploy": "NODE_ENV=production webpack -p"} / /... }Copy the code

Demo01: entry file

The import file is used by Webpack to read it and build bundle.js for example, main.js is an import file

// main.js
document.write('<h1>Hello World</h1>');
Copy the code

index.html

<html>
  <body>
    <script type="text/javascript" src="bundle.js"></script>
  </body>
</html>
Copy the code

Webpack builds bundle.js from webpack.config.js

// webpack.config.js
module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'}};Copy the code

Run the following command and go to http://127.0.0.1:8080

$ cd demo01
$ npm run dev
Copy the code

Demo02: Multiple entry files

Webpack allows multiple entry files to exist, which is useful in multi-page apps where each page has a different entry file.

// main1.js
document.write('<h1>Hello World</h1>');

// main2.js
document.write('<h2>Hello Webpack</h2>');
Copy the code

index.html

<html>
  <body>
    <script src="bundle1.js"></script>
    <script src="bundle2.js"></script>
  </body>
</html>
Copy the code

webpack.config.js

module.exports = {
  entry: {
    bundle1: './main1.js',
    bundle2: './main2.js'
  },
  output: {
    filename: '[name].js'}};Copy the code

Demo03:Babel-loader

Loaders are preprocessors that convert resource files in your app before the Webpack build process. For example, Babel-Loader can turn JSX/ES6 files into regular JS files, after which Webpack can start building them. Webpack official documentation has a list of loaders at the address main. JSX is a JSX file

// main.jsx
const React = require('react');
const ReactDOM = require('react-dom'); ReactDOM.render( <h1>Hello, world! </h1>, document.querySelector('#wrapper'));Copy the code

index.html

<html>
  <body>
    <div id="wrapper"></div>
    <script src="bundle.js"></script>
  </body>
</html>
Copy the code

webpack.config.js

module.exports = {
  entry: './main.jsx',
  output: {
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.jsx? $/, exclude: /node_modules/, use: { loader:'babel-loader',
          options: {
            presets: ['es2015'.'react'}}}]}};Copy the code

In the above code, two plug-ins of babel-Loader, babel-preset- ES2015 and babel-preset-react, are needed to switch ES6 and react.

Demo04:CSS-loader

Webpack allows CSS to be included in JS files that require CSS-loader to process main.js

require('./app.css');
Copy the code

app.css

body {
  background-color: blue;
}
Copy the code

index.html

<html>
  <head>
    <script type="text/javascript" src="bundle.js"></script>
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>
Copy the code

webpack.config.js

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  module: {
    rules:[
      {
        test: /\.css$/,
        use: [ 'style-loader'.'css-loader']},]}};Copy the code

Attention! You must use two loaders to transform CSS files. Css-loader is used to read CSS files for conversion, and another style-loader inserts < Style > tags into the HTML. And then open up the server

$ cd demo04
$ npm run dev
Copy the code

In fact, Webpack inserts the contents of the CSS file directly into index.html

<head>
  <script type="text/javascript" src="bundle.js"></script>
  <style type="text/css">
    body {
      background-color: blue;
    }
  </style>
</head>
Copy the code

Demo5: Image loader

Webpack can include images in the JS file main.js

var img1 = document.createElement("img");
img1.src = require("./small.png");
document.body.appendChild(img1);

var img2 = document.createElement("img");
img2.src = require("./big.png");
document.body.appendChild(img2);
Copy the code

index.html

<html>
  <body>
    <script type="text/javascript" src="bundle.js"></script>
  </body>
</html>
Copy the code

webpack.config.js

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  module: {
    rules:[
      {
        test: /\.(png|jpg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192}}]}};Copy the code

Url-loader converts the image file to a tag. If the image size is 8192 bytes, it converts the image to a Data URL. Otherwise, it converts the image to a normal file URL.

<img src="data:image/png; base64,iVBOR... uQmCC">
<img src="4853ca667a2b8b8844eb2693ac1b2578.png">
Copy the code

Demo06:CSS Module

css-loader? Modules can use CSS Modules, which give you a local scope for the CSS in your JS file Module, or global(selector) to make CSS global. index.html

<html>
<body>
  <h1 class="h1">Hello World</h1>
  <h2 class="h2">Hello Webpack</h2>
  <div id="example"></div>
  <script src="./bundle.js"></script>
</body>
</html>
Copy the code

app.css

/ *local scope */
.h1 {
  color:red;
}

/* global scope */
:global(.h2) {
  color: blue;
}
Copy the code

main.jsx

var React = require('react');
var ReactDOM = require('react-dom');
var style = require('./app.css');

ReactDOM.render(
  <div>
    <h1 className={style.h1}>Hello World</h1>
    <h2 className="h2">Hello Webpack</h2>
  </div>,
  document.getElementById('example'));Copy the code

webpack.config.js

module.exports = {
  entry: './main.jsx',
  output: {
    filename: 'bundle.js'
  },
  module: {
    rules:[
      {
        test: /\.js[x]? $/, exclude: /node_modules/, use: { loader:'babel-loader',
          options: {
            presets: ['es2015'.'react'}}}, {test: /\.css$/,
        use: [
          {
            loader: 'style-loader'
          },
          {
             loader: 'css-loader',
             options: {
               modules: true}}]}};Copy the code

Visit http://127.0.0.1:8080 and you’ll see that only H1 is red because its CSS is local scoped, and h2 is blue because it’s global scoped.

Demo07:UglifyJs Plugin

Webpack uses a plug-in system to extend its functionality. For example, the UglifyJs Plugin is used to compress JS code and make JS files smaller. main.js

var longVariableName = 'Hello';
longVariableName += ' World';
document.write('<h1>' + longVariableName + '</h1>');
Copy the code

index.html

<html>
<body>
  <script src="bundle.js"></script>
</body>
</html>
Copy the code

webpack.config.js

var webpack = require('webpack');
var UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new UglifyJsPlugin()
  ]
};
Copy the code

After accessing the server, you can see main.js minimized to the following code:

var o="Hello"; o+=" World",document.write("<h1>"+o+"</h1>")
Copy the code

(Translation: in the last few code of bundle.js, here’s the code)

Demo08:HTML Webpack Plugin and Open Browser Webpack Plugin

Html-webpack-plugin can create index.html for you. Open-browser-webpack-plugin can open a new browser TAB (TAB) main.js when webpack loads

document.write('<h1>Hello World</h1>');
Copy the code

webpack.config.js

var HtmlwebpackPlugin = require('html-webpack-plugin');
var OpenBrowserPlugin = require('open-browser-webpack-plugin');

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new HtmlwebpackPlugin({
      title: 'Webpack-demos',
      filename: 'index.html'
    }),
    new OpenBrowserPlugin({
      url: 'http://localhost:8080'}})];Copy the code

Now you don’t have to manually create index.html or open a browser.

Demo09: Environment Flags

Using environment variables makes some code available only in the development environment. main.js

document.write('<h1>Hello World</h1>');

if (__DEV__) {
  document.write(new Date());
}
Copy the code

index.html

<html>
<body>
  <script src="bundle.js"></script>
</body>
</html>
Copy the code

webpack.config.js

var webpack = require('webpack');

var devFlagPlugin = new webpack.DefinePlugin({
  __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))}); module.exports = { entry:'./main.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [devFlagPlugin]
};
Copy the code

Now pass the environment variables to Webpack. Open demo09/package.json and find the following scripts option

// package.json
{
  // ...
  "scripts": {
    "dev": "cross-env DEBUG=true webpack-dev-server --open",}, / /... }Copy the code

Demo10: Code separation

In large Web applications, putting all your code in one file is inefficient. Webpack allows you to split large JS files into chunks. In particular, if some code blocks are needed only in certain circumstances, they will be loaded on demand. Webpack uses require.ensure to define a split point

// main.js
require.ensure(['./a'].function (require) {
  var content = require('./a');             
  document.open();
  document.write('<h1>' + content + '</h1>');
  document.close();
});
Copy the code

Require. Ensure tells Webpack./ A that js needs to be separated from bundle.js as a separate block file

// a.js
module.exports = 'Hello World';
Copy the code

Now Webpack cares about dependencies, output files, runtime stuff. You don’t have to put extra stuff in index.html and webpack.config.js

<html>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>
Copy the code


webpack.config.js

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'}};Copy the code

After visiting the server, you will not feel any difference. In fact, Webpack will build main.js and A.js into different blocks (bundle.js and 0.bundle.js) and then load 0.bundle.js on demand from bundle.js

Demo11: Code separation under bundle-loader

Another way to split code is bundle-loader

// main.js

// Now a.js is requested, it will be bundled into another file
var load = require('bundle-loader! ./a.js');

// To wait until a.js is available (and get the exports)
//  you need to async wait for it.
load(function(file) {
  document.open();
  document.write('<h1>' + file + '</h1>');
  document.close();
});
Copy the code

require(‘bundle-loader! ./a.js’) tells Webpack to load A.js from other blocks. Now main.js is built as bundle.js, and a.js is built as 0.bundle.js

Demo12: general block

There are common blocks in multiple JS scripts. With the CommonsChunkPlugin you can extract common parts from different files, which is very useful for browser caching to save bandwidth.

// main1.jsx
var React = require('react');
var ReactDOM = require('react-dom');

ReactDOM.render(
  <h1>Hello World</h1>,
  document.getElementById('a')); // main2.jsx var React = require('react');
var ReactDOM = require('react-dom');

ReactDOM.render(
  <h2>Hello Webpack</h2>,
  document.getElementById('b'));Copy the code

index.html

<html>
  <body>
    <div id="a"></div>
    <div id="b"></div>
    <script src="commons.js"></script>
    <script src="bundle1.js"></script>
    <script src="bundle2.js"></script>
  </body>
</html>
Copy the code

Commons.js above is a common part of main1.jsx and main2.jsx. As you might expect, commons.js includes react and react-dom webpack.config.js

var webpack = require('webpack');

module.exports = {
  entry: {
    bundle1: './main1.jsx',
    bundle2: './main2.jsx'
  },
  output: {
    filename: '[name].js'
  },
  module: {
    rules:[
      {
        test: /\.js[x]? $/, exclude: /node_modules/, use: { loader:'babel-loader',
          options: {
            presets: ['es2015'.'react']
          }
        }
      },
    ]
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: "commons",
      // (the commons chunk name)

      filename: "commons.js",
      // (the filename of the commons chunk)
    })
  ]
}
Copy the code

Demo13:Vendor chunk

With CommonsChunkPlugin, you can extract the official library from JS scripts into a separate file called main.js

var $ = require('jquery');
$('h1').text('Hello World');
Copy the code

index.html

<html>
  <body>
    <h1></h1>
    <script src="vendor.js"></script>
    <script src="bundle.js"></script>
  </body>
</html>
Copy the code

webpack.config.js

var webpack = require('webpack');

module.exports = {
  entry: {
    app: './main.js',
    vendor: ['jquery'],
  },
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      filename: 'vendor.js'}})];Copy the code

In the code above, Entry.vendor :[‘jquery’] tells Webpack that jquery should be included in the generic block vendor.js. If you want a module to be used as a global variable in different modules, such as $or jquery instead of requiring (‘jquery’) in every file, use the ProvidePlugin. It automatically loads modules without needing to import or require them everywhere

// main.js
$('h1').text('Hello World');


// webpack.config.js
var webpack = require('webpack');

module.exports = {
  entry: {
    app: './main.js'
  },
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery'}})];Copy the code

Of course, in Demo13, you need to load jquery.js globally yourself

Demo14: Exposes global variables

If you want to use global variables, you don’t need to include them in the Webpack, you can use the externals field in webpack.config.js. For example, we have a data.js

// data.js
var data = 'Hello World';
Copy the code

index.html

<html>
  <body>
    <script src="data.js"></script>
    <script src="bundle.js"></script>
  </body>
</html>
Copy the code

Note that Webpack only builds bundle.js, not data.js. We can use data as a global variable

// webpack.config.js
module.exports = {
  entry: './main.jsx',
  output: {
    filename: 'bundle.js'
  },
  module: {
    rules:[
      {
        test: /\.js[x]? $/, exclude: /node_modules/, use: { loader:'babel-loader',
          options: {
            presets: ['es2015'.'react']
          }
        }
      },
    ]
  },
  externals: {
    // require('data') is external and available
    //  on the global var data
    'data': 'data'}};Copy the code

At this point, you can require(‘data’) as a module variable, which is actually a global variable

// main.jsx
var data = require('data');
var React = require('react');
var ReactDOM = require('react-dom');

ReactDOM.render(
  <h1>{data}</h1>,
  document.body
);
Copy the code

You can also add react and react-dom to externals, which significantly reduces the bundle.js build time and file size

Demo15:React router

This Demo uses Webpack to build an official React Router. Imagine a small application with a dashboard, inbox, and calendar

+---------------------------------------------------------+ | +---------+ +-------+ +--------+ | | |Dashboard| | Inbox |  |Calendar| Loggedinas Jane | | +---------+ +-------+ +--------+ | +---------------------------------------------------------+ | | | Dashboard | | | | | | +---------------------+ +----------------------+ | | | | | | | | | + + | +---------> | | | | | | |  | | | | | | + | | +-------------> | | | | | | + | | | | | | | | | | | | | | | | +-+---+----+-----+----+ +----------------------+ | | | +---------------------------------------------------------+Copy the code

webpack.config.js

module.exports = {
  entry: './index.js',
  output: {
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [ 'style-loader'.'css-loader'] {},test: /\.jsx? $/, exclude: /node_modules/, use: { loader:'babel-loader',
          options: {
            presets: ['es2015'.'react']}}},]}};Copy the code

index.js

import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter, Switch, Route, Link } from 'react-router-dom';

import './app.css';

class App extends React.Component {
  render() {
    return (
      <div>
        <header>
          <ul>
            <li><Link to="/app">Dashboard</Link></li>
            <li><Link to="/inbox">Inbox</Link></li>
            <li><Link to="/calendar">Calendar</Link></li>
          </ul>
          Logged in as Jane
        </header>
        <main>
          <Switch>
            <Route exact path="/" component={Dashboard}/>
            <Route path="/app" component={Dashboard}/>
            <Route path="/inbox" component={Inbox}/>
            <Route path="/calendar" component={Calendar}/>
            <Route path="*"component={Dashboard}/> </Switch> </main> </div> ); }}; class Dashboard extends React.Component {render() {
    return( <div> <p>Dashboard</p> </div> ); }}; class Inbox extends React.Component {render() {
    return( <div> <p>Inbox</p> </div> ); }}; class Calendar extends React.Component {render() {
    return( <div> <p>Calendar</p> </div> ); }}; render(( <BrowserRouter> <Route path="/" component={App} />
  </BrowserRouter>
), document.querySelector('#app'));
Copy the code

index.html

<html>
  <body>
    <div id="app"></div>
    <script src="/bundle.js"></script>
  </body>
</htmL>

Copy the code

Then go to http://127.0.0.1:8080