zoukankan      html  css  js  c++  java
  • webpack 多页面|入口支持和公共组件单独打包--转载

    转载自:http://www.jb51.net/article/117490.htm

    本篇主要介绍:如何自动构建入口文件,并生成对应的output;公共js库如何单独打包。

    多入口文件,自动扫描入口。同时支持SPA和多页面型的项目

    公共js库如何单独打包。

    基础结构和准备工作

    以下示例基于上一篇进行改进,上一篇项目源码

    目录结构说明

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    .
    ├── package.json    # 项目配置
    ├── src      # 源码目录
    │ ├── pageA.html    # 入口文件a
    │ ├── pageB.html    # 入口文件b
    │ ├── css/     # css资源
    │ ├── img/     # 图片资源
    │ ├── js     # js&jsx资源
    │ │ ├── pageA.js    # a页面入口
    │ │ ├── pageB.js    # b页面入口
    │ │ ├── lib/    # 没有存放在npm的第三方库或者下载存放到本地的基础库,如jQuery、Zepto、avalon
    │ ├── pathmap.json   # 手动配置某些模块的路径,可以加快webpack的编译速度
    ├── webpack.config.js   # webpack配置入口

    一:自动构建入口

    官方多入口示例

    webpack默认支持多入口,官方也有多入口的示例。配件文件webpack.config.js如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //已简化
    var path = require("path");
    module.exports = {
     entry: {
      pageA: "./pageA",
      pageB: "./pageB"
     },
     output: {
      path: path.join(__dirname, "js"),
      filename: "[name].bundle.js",
      chunkFilename: "[id].chunk.js"
     }
    }

    每新增一个页面就需要在webpack.config.js的entry 中增加一个 pageC:"./pageC",页面少还好,页面一多,就有点麻烦了,而且配置文件,尽可能不改动。那么如何支持不修改配置呢?

    自动构建入口函数

    entry实际上是一个map对象,结构如下{filename:filepath},那么我们可以根据文件名匹配,很容易构造自动扫描器:
    npm 中有一个用于文件名匹配的 glob模块,通过glob很容易遍历出src/js目录下的所有js文件:

    安装glob模块

    1
    $ npm install glob --save-dev

    修改webpack.config.js 配置,新增entries函数,修改entry:entries(),修改output的filename为"[name].js"

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    //引入glob
    var glob = require('glob')
    //entries函数
    var entries= function () {
     var jsDir = path.resolve(srcDir, 'js')
     var entryFiles = glob.sync(jsDir + '/*.{js,jsx}')
     var map = {};
     
     for (var i = 0; i < entryFiles.length; i++) {
      var filePath = entryFiles[i];
      var filename = filePath.substring(filePath.lastIndexOf('/') + 1, filePath.lastIndexOf('.'));
      map[filename] = filePath;
     }
     return map;
    }
    //修改入口,已经修改outp的filename
    module.exports = {
     //entry: "./src/js/index.js",
     entry: entries(),
     output: {
      path: path.join(__dirname, "dist"),
      filename: "[name].js"
     },
     ......
     //以下省略,可以见下文详细配置

    测试

    1.在src/js目录中新增pageA.js

    1
    2
    3
    //js只有两行代码,在body中加一句话
    var $ = require("jquery")
    $("<div>这是jquery生成的多页面示例</div>").appendTo("body")

    2.新增pageA.html,也顺便修改原来的index.html 对于js文件名的更改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title></title>
    </head>
    <body>
    <script src="../dist/index.js"></script>
    </body>
    </html>

    3.执行webpack,启动dev-server

    1
    2
    $ webpack
    $ webpack-dev-server

    OK,成功打包生成pageA.js,成功运行

    二:公共库单独打包

    先来分析下,上个步骤打包的日志:

    index.js 依赖了avalon 和 jquery,然后打包后的index.js 有480kb

    pageA.js 只用了jquery,然后打包后的js 有294kb

    那么如果引用的lib库多一点,又被很多页面引用,那么lib库就会被重复打包到page.js中去,模块越多重复加载的情况越严重。

    如果把公共代码提取出来作为单独的js,那么就到处可以复用,浏览器也就可以进行缓存,这时候就需要用到webpack内置插件WebPack.optimize.CommonsChunkPlugin

    CommonsChunkPlugin 介绍

    使用

    1
    new webpack.optimize.CommonsChunkPlugin(options)

    Options
    翻译得比较简单,详见官方说明:

    1. options.name or options.names(string|string[]): 公共模块的名称
    2. options.filename (string): 公开模块的文件名(生成的文件名)
    3. options.minChunks (number|Infinity|function(module,count) - boolean): 为number表示需要被多少个entries依赖才会被打包到公共代码库;为Infinity 仅仅创建公共组件块,不会把任何modules打包进去。并且提供function,以便于自定义逻辑。
    4. options.chunks(string[]):只对该chunks中的代码进行提取。
    5. options.children(boolean):如果为true,那么公共组件的所有子依赖都将被选择进来
    6. options.async(boolean|string):如果为true,将创建一个 option.name的子chunks(options.chunks的同级chunks) 异步common chunk
    7. options.minSize(number):所有公共module的size 要大于number,才会创建common chunk

    2个常用的例子,更多例子见官方说明:

    1.Commons chunk for entries:针对入口文件提取公共代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    new CommonsChunkPlugin({
     name: "commons",
     // (the commons chunk name)
     
     filename: "commons.js",
     // (the filename of the commons chunk)
     
     // minChunks: 3,
     // (Modules must be shared between 3 entries)
     
     // chunks: ["pageA", "pageB"],
     // (Only use these entries)
    })

    2.Explicit vendor chunk:直接指定第三方依赖库,打包成公共组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    entry: {
     vendor: ["jquery", "other-lib"],
     app: "./entry"
    }
    new CommonsChunkPlugin({
     name: "vendor",
     
     // filename: "vendor.js"
     // (Give the chunk a different name)
     
     minChunks: Infinity,
     // (with more entries, this ensures that no other module
     // goes into the vendor chunk)
    })

    CommonsChunkPlugin使用

    基于上篇的项目,参考上面的第二个例子,我们将jquery 和 avalon 提取出来打包成vendor.js

    完整的webpack.config.js 如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    ```js
    var webpack = require("webpack");
     var path = require("path");
     var srcDir = path.resolve(process.cwd(), 'src');
     var nodeModPath = path.resolve(__dirname, './node_modules');
     var pathMap = require('./src/pathmap.json');
     var glob = require('glob')
     var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
     var entries= function () {
     var jsDir = path.resolve(srcDir, 'js')
     var entryFiles = glob.sync(jsDir + '/*.{js,jsx}')
     var map = {};
     for (var i = 0; i < entryFiles.length; i++) {
      var filePath = entryFiles[i];
      var filename = filePath.substring(filePath.lastIndexOf('/') + 1, filePath.lastIndexOf('.'));
      map[filename] = filePath;
     }
     return map;
    }
     
    module.exports = {
     //entry: "./src/js/index.js",
     //entry: entries(),
     entry: Object.assign(entries(), {
      // 用到什么公共lib(例如jquery.js),就把它加进vendor去,目的是将公用库单独提取打包
      'vendor': ['jquery', 'avalon']
     }),
     output: {
      path: path.join(__dirname, "dist"),
      filename: "[name].js"
     },
     module: {
      loaders: [
       {test: /.css$/, loader: 'style-loader!css-loader'}
      ]
     },
     resolve: {
      extensions: ['.js', "", ".css"],
      root: [srcDir,nodeModPath],
      alias: pathMap,
      publicPath: '/'
     },
     plugins: [
      new CommonsChunkPlugin({
       name: 'vendor',
       minChunks: Infinity
      })
     ]
    }
    ```

    测试、验证

    1.修改入口(Object.assign 是html5.js里面的....)

    1
    2
    3
    4
    5
    //entry: entries(),
    entry: Object.assign(entries(), {
     // 用到什么公共lib(例如jquery.js),就把它加进vendor去,目的是将公用库单独提取打包
     'vendor': ['jquery', 'avalon']
    }),

    2.加入插件CommonsChunkPlugin

    1
    2
    3
    4
    5
    6
    7
    8
    var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
    config 中增加 plugins
     plugins: [
      new CommonsChunkPlugin({
       name: 'vendor',
       minChunks: Infinity
      })
     ]

    3.修改index.html 和 pageA.html,增加对verdor.js的引用

    1
    2
    3
    <script src="../dist/vendor.js"></script>
    <script src="../dist/index.js"></script>
    //<script src="../dist/pageA.js"></script>

    4.执行webpack

    $ webpack

    结果分析

    可以看到index.js 就只有457 bytes了,pageA.js 227bytes。vendor.js 是集成了jquery+avalon,所以有488kb。

    这样vendor.js 就可以重复利用了,也方便浏览器进行缓存。

    调试过程中发现

    Uncaught ReferenceError: webpackJsonp is not defined

    这个是因为当时把vendor.js引入 放到了page.js 后面,导致page.js执行异常,所以,请一定把vendor.js 放在前面。

    生成后的index.js就很轻便了,第三方库都被打包到vendor中了,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    webpackJsonp([0],[
    /* 0 */
    /***/ function(module, exports, __webpack_require__) {
     
     /**
      * Created by sloong on 2016/6/1.
      */
     //avalon 测试
     var avalon = __webpack_require__(1);
     avalon.define({
      $id: "avalonCtrl",
      name: "Hello Avalon!"
     });
     
     /*
     //zepto 测试
     require("zepto")
     
     $("<div>这是zepto生成的</div>").appendTo("body")*/
     
     //jquery 测试
     var $ = __webpack_require__(2)
     $("<div>这是jquery生成的</div>").appendTo("body")
     
    /***/ }
    ]);

    页面测试均正常

    OK,本篇结束了。如何让webpack 自动在html文件中引入所需js的script标签,如何给js和css文件加了hash值,这样浏览器每次都能检测到文件变更,而且也不需要手动修改引入的js文件链接,这些操作webpack都能轻松搞定。

  • 相关阅读:
    30分钟用Restful ABAP Programming模型开发一个支持增删改查的Fiori应用
    SAP Marketing Cloud功能简述(一) : Contacts和Profiles
    如何使用点击超链接的方式打开Android手机上的应用
    1036. Boys vs Girls (25)
    Yet another A + B
    1033. To Fill or Not to Fill (25)
    1032. Sharing (25)
    1021. Deepest Root (25)
    1017. Queueing at Bank (25)
    1016. Phone Bills (25)
  • 原文地址:https://www.cnblogs.com/xiangxinhouse/p/8544766.html
Copyright © 2011-2022 走看看