美文网首页
webpack-demos

webpack-demos

作者: 小飞牛牛 | 来源:发表于2021-05-06 20:13 被阅读0次

阮一峰老师的webpack教程,这个webpack-demo 基于webpack 3.10.0 ,与最新的webpack配置可能存在差别。
https://github.com/ruanyf/webpack-demos

demo01

这是最简单的一个配置,entry 配置入口文件地址,output配置目标文件地址。
生成后的文件是经过压缩的。

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

demo02

多入口文件,一个目标文件。filename 文件名生成后为 bundle1和bundle2, 使用[name] 作为标识

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

demo3

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

这里有几个信息。输入的文件不再是js,因此需要引入babel-loader, 这个在package.json中有引入

"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",

通过babel-loader,将jsx文件转换成js文件。rules 配置的细节先不做探究,那是loader的行为。
另外,main.jsx中有对 react和react-dom的引入,其实是react-router包产生的依赖。

demo04

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

入口文件和目标文件都是js文件,但不同的是: 入口js文件引入了一个css文件

require('./app.css');

因此需要style-loader和css-loader, 事实上它会从后向前解析,先调用css-loader解析css,再调用style-loader将样式添加到头部的逻辑加上。

demo05

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

这个例子引入了图片资源,
注意它使用的是url-loader, 这个loader是图片的获取url后返回到当前位置。
留意到options的limit参数,单位是字节,凡是小于这个字节数的图片文件,都会转成base64字符串,不大于的才返回url。
另外还有其它选项:

{
    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
    loader: 'url-loader',
    include: [resolve('static'),resolve('src')],
    options: {
        limit: 100000,
        name: utils.assetsPath('img/[name].[hash:7].[ext]')
    }
}

name就是自定义image的路径以及name,include就是你想让哪个文件夹里面的图片进行url-loader转换

demo06

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
             }
          }
        ]
      }
    ]
  }
};

这个demo展示了如何多个loader同时使用的状况。另外展示了use参数的多种传值方式。

use的参数可以是:字符串数组,对象,对象数组。

在这里看到css-loader的options参数有个modules,实际上每个loader有不一样的参数。

demo06

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

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

这个例子展示了插件的使用。

插件通过plugins 数组引入。

UglifyJsPlugin 插件的作用是将js进行压缩

如果不用这个插件,看看文件大小

    Asset       Size  Chunks             Chunk Names
bundle.js  537 bytes       0  [emitted]  main
   [0] ./main.js 118 bytes {0} [built]

如果用这个插件

   Asset       Size  Chunks             Chunk Names
bundle.js  537 bytes       0  [emitted]  main
   [0] ./main.js 118 bytes {0} [built]

大小一样?翻车了,看到怀疑人生。。。
这个先不管吧

demo08

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'
    })
  ]
};

这里展示了另外两个插件

HtmlwebpackPlugin

该插件的作用

为html文件中引入的外部资源如script、link动态添加每次compile后的hash,防止引用缓存的外部文件问题

可以生成创建html入口文件,比如单页面可以生成一个html文件入口,配置N个html-webpack-plugin可以生成N个页面入口

当你的入口文件是js文件时,用这个插件可以自动生成一个入口html文件,将生成后的js文件插入到Html中

运行

npm run build

打印出信息

Child html-webpack-plugin for "index.html":
     1 asset
       [2] (webpack)/buildin/global.js 509 bytes {0} [built]
       [3] (webpack)/buildin/module.js 517 bytes {0} [built]
        + 2 hidden modules

既然如此,尝试增加一个页面

 plugins: [
    new HtmlwebpackPlugin({
      title: 'Webpack-demos',
      filename: 'index.html'
    }),
    new HtmlwebpackPlugin({
      title: 'Webpack-demos',
      filename: 'entry.html'
    }),
    new OpenBrowserPlugin({
      url: 'http://localhost:8080'
    })
  ]

成功生成了两个页面

Child html-webpack-plugin for "index.html":
     1 asset
       [2] (webpack)/buildin/global.js 509 bytes {0} [built]
       [3] (webpack)/buildin/module.js 517 bytes {0} [built]
        + 2 hidden modules
Child html-webpack-plugin for "entry.html":
     1 asset
       [2] (webpack)/buildin/global.js 509 bytes {0} [built]
       [3] (webpack)/buildin/module.js 517 bytes {0} [built]
        + 2 hidden modules

OpenBrowserPlugin

运行

npm run dev

编译后自动打开浏览器,可以看到浏览器的端口号就是参数指定的端口号。每个插件都有不同的功能参数,应该逐个研究,这里就只是了解吧。

demo09

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]
};

main.js

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

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

从代码可以看到, DefinePlugin插件定义了一个全局变量,注入到js中,js中可以直接使用

demo10

webpack.config.js

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

main.js

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

可以看到,webpack.config.js其实没有变化。关键在main.js 里面使用了require.ensure方法 。

这应该是一个异步引入模块的方法。在找这个模块的时候,webpack 会自动把这个模块单独打包。

单页应用的路由页面独立出一个js文件,还有异步组件应该就是使用这种机制。

      Asset       Size  Chunks             Chunk Names
0.bundle.js  110 bytes       0  [emitted]
  bundle.js    6.05 kB       1  [emitted]  main
   [0] ./a.js 33 bytes {0} [built]
   [1] ./main.js 171 bytes {1} [built]

它会将模块打包成0.bundle.js文件,
然后在bundle.js文件中引入。

__webpack_require__.e/* require.ensure */(0).then((function(require) {
  var content = __webpack_require__(0);
  document.open();
  document.write('<h1>' + content + '</h1>');
  document.close();
}).bind(null, __webpack_require__)).catch(__webpack_require__.oe);

这个打包后的bundle.js其实是使用了jsonp的方法去实现的。

webpack_require 这种模块化加载形式从demo08 开始,就在bundle.js中出现,之前的只是简单地对文件转换,压缩。

然而demo08并没有引入模块。所以,它除了跟入口文件引入模块有关,还跟插件本身的处理有关。

demo11

main.js

var load = require('bundle-loader!./a.js');

load(function(file) {
  document.open();
  document.write('<h1>' + file + '</h1>');
  document.close();
});

webpack.config.js

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

main.js中使用了bundle-loader加载模块,这是在文件中使用loader,而非webpack配置

demo12

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)
    })
  ]
}

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(
  <h1>Hello World</h1>,
  document.getElementById('a')
);

main1.jsx和main2.jsx两个文件都引入了react和react-dom, 在webpack配置中,CommonsChunkPlugin可将共同引入的模块抽出来,打包到common.js中。(其实,只要引了这个插件,即使没有公共的模块,也会生成common.js)

demo13

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'
    })
  ]
};

main.js

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

在main.js中引入了jquery, 在entry中定义vendor,可以将指定的模块打包到公共包中。

如果在entry中将vendor注释掉,生成的vendor.js中,不会包含jquery,而是被包含到了bundle.js中

Asset     Size  Chunks                    Chunk Names
bundle.js   289 kB       0  [emitted]  [big]  app
vendor.js  5.78 kB       1  [emitted]         vendor

demo14

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'
  }
};

main.jsx

var data = require('data');
var React = require('react');
var ReactDOM = require('react-dom');

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

该例展示了externals 选项的用法,定义了一个data变量,在main.jsx中require获得,可以直接使用。
试与 demo09的DefinePlugin插件比较

demo15

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']
          }
        }
      },
    ]
  }
};

index.js

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

import './app.css';

// ref https://stackoverflow.com/questions/46482433/reactjs-createclass-is-not-a-function
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>
    );
  }
};

// ref https://segmentfault.com/q/1010000009616045/a-1020000009618728
render((
  <BrowserRouter>
    <Route path="/" component={App} />
  </BrowserRouter>
), document.querySelector('#app'));

展示了一个较为综合的react例子

相关文章

网友评论

      本文标题:webpack-demos

      本文链接:https://www.haomeiwen.com/subject/vzaddltx.html