Time: 20190925

在前面的文章中我们讲到的都是关于模块的组装,现在我们进入到一个新的话题:前端工程涉及到的资源是从哪里来,组装后送到哪里去的问题。

本文主要涉及到三个字段的配置:

  • context
  • entry
  • output

一、资源的处理流程

Webpack资源处理流程

事情的开始是:指定入口。

这和我们写任何语言的代码是一样的道理,程序的入口是一切一切的开始。

同样,资源处理,也是要从入口开始着手。所谓资源处理,就是Webpack进行资源的打包。所谓入口,就是打包从源码目录的哪个文件开始打包。

以树的角度思考,入口就是这棵资源树的根。

chunk

存在依赖关系的模块在打包完毕后,会成为一个代码块,英文名称叫chunk

一个工程打包后会形成一个或多个chunk,具体取决于配置。

打包流程

Webpack从入口文件开始检索,将有依赖关系的模块生成一个依赖树,打包完成后形成一个chunk。

chunk在完成打包后的产物我们一般称作bundle

一个工程中可以有多个入口,每个入口会产生一个结果资源bundle。

或者,一个入口也可以产生多个chunk,最终产生多个bundle,这些情形会在后续的文章中仔细道来。

二、配置资源入口

主要讲两个配置项的作用:

  • context
  • entry

这两个配置项会共同决定入口文件的路径

配置入口到底做了什么?

两件事:

  1. 确定入口模块的位置,告诉Webpack从哪里开始打包
  2. 定义chunk名称,当工程只有一个入口时,默认chunk的名字为main,如果有多个入口,则需要为每个入口定义它的chunk名称,chunk名称是chunk的唯一标识

context

无论是哪种语言,context都是一个非常重要的概念。中文含义为上下文,处于上下文中的对象,可以向上下文获取很多有用的信息。在这里,context的含义比较简单明确:资源入口的路径前缀

这个字段必须是绝对路径。

下面的代码片段的例子:

module.exports = {context: path.join(__dirname, './src'),entry: './scripts/index.js',
};// 下面这种方式和上面效果一致
module.exports = {context: path.join(__dirname, './src/scripts'),entry: './index.js',
};

这个字段的目的就是为了简化entry字段的填写。

默认是当前工程的根目录,且context的类型只能为字符串。

entry

entry的类型可以是:

  • 字符串
  • 数组
  • 对象
  • 函数

下面将分别展开。

字符串类型入口

module.exports = {entry: './src/index.js',output: {filename: "bundle.js",},mode: 'development',
};

数组类型入口

既然是找入口,上面字符串类型的,只有一个选项,默认就是入口,如果给了一个数组,则需要一个约定,这个约定就是:

数组的最后一个元素是实际的入口路径。

那么数组其他元素有什么作用呢?

答案就是:将多个资源预先整合

如下面的例子:

module.exports = {entry: ['babel-polyfill', './src/index.js'],
};

所谓预先整合就是提到的文件会预先导入到入口。

上面的配置相当于:

// webpack.config.js
module.exports = {entry: './src/index.js',
};// index.js
import 'babel-polyfill';

对象类型入口

这种用法主要针对的是多入口,如果是多入口,就必须用对象的形式。

其中,对象的属性名是chunk name,属性值对应的是入口路径。

module.exports = {entry: {index: './src/index.js',lib: './src/lib.js',},
};

上面这段代码,定义了两个chunk name,分别是indexlib

对象类型入口这里的属性值可以用数组类型,效果和单独使用数组类型效果相同。

module.exports = {entry: {index: ['babel-polyfill', './src/index.js'],lib: './src/lib.js',},
};

对象类型入口必须手动指定chunk name,而上面的两种方式则都不能指定,用的是默认的main名称。

函数类型入口

函数类型入口返回的结果必须是上面三种入口的一种,不过既然是函数,我们就可以添加一些动态逻辑以获取入口,比如用Promise支持异步操作。

// 返回字符串型入口
module.exports = {entry: () => './src/index.js',
};// 返回对象型入口
module.exports = {entry: () => ({index: ['babel-polyfill', './src/index.js'],lib: './src/index.js',}),
};

下面是异步操作获取入口的例子:

module.exports = {entry: () => new Promise((resolve)) => {// 模拟异步操作setTimeout(() => {resolve('./src/index.js');}, 1000);},
};

举例子

下面我们进入实例阶段。

单页应用SPA

单页应用一般选用的方式是:定义一个单一入口。

module.exports = {entry: './src/app.js',
};

这样,框架、库、各个页面的模块,都统一由app.js这个入口进行引用。

单一入口的利与弊:

  • 利:只产生一个JS文件,依赖关系清晰
  • 弊:所有模块打包在一起,应用规模过大时,产生的资源体积过大,前端渲染速度过慢,影响用户的使用体验

在webpack打包时,当打包的bundle大于250KB时,会发出警告。

那么有什么解决办法呢?

提取vendor

vendor这个单词,有小卖部,摊贩,供应商的含义。这个想法比较简单直接,就是将工程用到的库,框架等第三方应用集中打包生成一个bundle

这样,前端不用在修改用户自定义代码时重新下载全部资源,只需要下载修改的资源即可

module.exports = {context: path.join(__dirname, './src'),entry: {app: './src/app.js',vendor: ['react', 'react-dom', 'react-router'],},
};

后面会讲到用optimization.splitChunks来把appvendor两个chunk中的公共模块抽取出来。这样干的结果就是,app.js作为入口形成的bundle只会包含业务代码,vendor包含了第三方模块,在客户端可以有效缓存,提升前端界面的加载效率。

多页应用

每个页面都有自己的独立的bundle,每个页面只加载各自的必要的逻辑,能减少资源的加载体积,从而能够提升页面的加载速度。

例子如下:

module.exports = {entry: {pageA: './src/pageA.js',pageB: './src/pageB.js',pageC: './src/pageC.js',},
};

同样,多页应用也可以提取vendor,将各自页面上用到的第三方模块抽取出来。

写法如下:

module.exports = {entry: {pageA: './src/pageA.js',pageB: './src/pageB.js',pageC: './src/pageC.js',vencor: ['react', 'react-dom', 'react-router'],},
};

提取vendor也需要结合optimization.splitChunks来一起使用,实现生成单独的bundle的效果。

三、配置资源出口

上面讲了一堆资源入口配置,主要涉及到的是entry字段的配置,在资源出口配置这里,主要是要讲output字段的配置。

const path = require('path');
module.exports = {entry: './src/app.js',output: {filename: 'bundle.js',path: path.join(__dirname, 'assets'),publicPath: '/dist',},
};

output对象中,有多大数十个配置选项,大部分情况下,下面几个是常用的:

  • filename
  • path
  • publicPath

filename

表示输出资源的文件名,即定义bundle的名字。或者,该字段也可以是相对路径,不存在也不影响,Webpack会自动创建目录。

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

下面的这种就是相对目录:

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

在多入口的情况下,需要的是为每个生成的bundle指定不同的名字,用的是一种动态推导的方式:

module.exports = {entry: {app: './src/index.js',vendor: './src/vendor.js',},output: {filename: '[name].js',},
};

打包时,[name]会被自动替换为chunk name

除了[name]这个模板变量外,还有其他选项:

  • [hash]
  • [chunkhash]
  • [id]
  • [query]

具体用法这里暂时不展开。

path

指定资源的是输出位置

必须为绝对路径。

默认为dist目录,一般不用单独配置。

publicPath

用于指定资源的请求位置。
这个配置项和webpack-dev-server中的publicPath有所不同,后者是开发服务器静态资源的服务路径。

2019.10 Update:

第一届PAT算法直播课培训班招募帖,欢迎点击查看详情、

END.

webpack资源的输入与输出相关推荐

  1. Python 基础--输入与输出

    有些时候你的程序会与用户产生交互.举个例子,你会希望获取用户的输入内容,并向用户打印出一些返回的结果.我们可以分别通过 input() 函数与 print 函数来实现这一需求. 对于输入,我们还可以使 ...

  2. Numpy入门教程:09. 输入和输出

    背景 什么是 NumPy 呢? NumPy 这个词来源于两个单词 – Numerical和Python.其是一个功能强大的 Python 库,可以帮助程序员轻松地进行数值计算,通常应用于以下场景: 执 ...

  3. python文件输入和输出

    第一步 排除文件打开方式错误: r只读,r+读写,不创建 w新建只写,w+新建读写,二者都会将文件内容清零 (以w方式打开,不能读出.w+可读写) w+与r+区别: r+:可读可写,若文件不存在,报错 ...

  4. python3中文手册-Python 输入和输出

    Python 输入和输出 在前面几个章节中,我们其实已经接触了 Python 的输入输出的功能.本章节我们将具体介绍 Python 的输入输出. 输出格式美化 Python两种输出值的方式: 表达式语 ...

  5. java 文件字节流_Java:文件字符流和字节流的输入和输出

    最近在学习Java,所以就总结一篇文件字节流和字符流的输入和输出. 总的来说,IO流分类如下: 输入输出方向:     输入流(从外设读取到内存)和输出流(从内存输出到外设) 数据的操作方式: 字节流 ...

  6. xml文件 卷积神经网络_理解卷积神经网络中的输入与输出形状(Keras实现)

    即使我们从理论上理解了卷积神经网络,在实际进行将数据拟合到网络时,很多人仍然对其网络的输入和输出形状(shape)感到困惑.本文章将帮助你理解卷积神经网络的输入和输出形状. 让我们看看一个例子.CNN ...

  7. python 3 输入和输出

    一.普遍的输入和输出 1.输入 在python3中,函数的输入格式为:input(),能够接受一个标准输入数据,返回string类型. input() 函数是从键盘作为字符串读取数据,不论是否使用引号 ...

  8. 小白都能玩的算法day2-数量级、输入和输出

    小白讲故事,每日都精彩. 今天小白要给大家带来什么故事呢?不,今天我们不讲故事.今天来学数学.~有趣 什么是数量级 什么鬼? 数量级? 头晕^V^^V^^V^ 数量级 路人甲:噢~~,小白原来你要教我 ...

  9. 全连接层的输入和输出_理解Web应用程序的本质,网络数据流处理与基础网络连接...

    前言 前面一篇文章,我从整个应用程序的整体以及跟运行环境的关系简单聊了一下我们现在常用的Spring框架的设计基础和原则,其中主要是控制反转和依赖注入,以及容器化编程等概念. 这里我不想去复述这些概念 ...

最新文章

  1. 论文作者串通抱团、威胁审稿人,ACM Fellow炮轰「同行评审」作弊
  2. 浅析Java虚拟机结构与机制
  3. android仿微信的activity平滑水平切换动画,Android实现简单底部导航栏 Android仿微信滑动切换效果...
  4. 吴恩达 coursera AI 专项五第一课(上)总结+作业答案
  5. Tomcat与Jre绿色环境配置(生产环境)
  6. 大话设计模式—命令模式
  7. 使用SpringTask定时获取传感器设备信息并缓存到Redis
  8. 最棒 Spring Boot 干货总结
  9. 博士生录取采用审核制,存在的一些明显问题!
  10. php theexcerpt,wordpress的excerpt()函数的用法示例
  11. CSS3动画框架 Animate.css
  12. Docker安装与入门
  13. Windows核心编程_窗口启动效果
  14. 吴恩达的21节Deeplearning.ai课程学习经验总结
  15. Reasoning methods include
  16. java 内存模型书籍_《深入理解 Java 内存模型》读书笔记
  17. rk3288 gpio控制
  18. 网络攻防原理及应用 知识梳理
  19. 如何带领好团队,增强团队的执行力?
  20. What is OpenVZ

热门文章

  1. gnuplot 使用时遇到的问题
  2. pycharm conda 环境 切换 linux_windows配置wsl2环境+pycharm指路
  3. html5动画在线制作工具,KoolShow-KoolShow(HTML5动画制作工具) v2.4.4 官方版-CE安全网...
  4. 关于python列表去重复后按照元列表序列输出
  5. python什么是接口设计_给女朋友讲什么叫接口设计!
  6. python复数运算程序_python复数-python,复数
  7. java线程间通信 实例_JAVA-初步认识-第十四章-线程间通信-示例
  8. java web 项目伪静态_【Java Web】使用URLRewrite实现网站伪静态
  9. Python数据结构与算法(2.1)——线性表的基本概念
  10. java功能模块_Java 14功能