通过核心概念了解webpack工作机制
webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
需要先理解四个核心概念:
- 入口(entry)
- 输出(output)
- loader
- 插件(plugins)
入口(entry)
入口指 webpack 构建其内部依赖图开始的模块。进入入口后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
在 webpack 配置中有多种方式定义 entry 属性。
用法:
- const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
单个入口可简写成如下:
- const config = {
entry: './path/to/my/entry/file.js'
};
以下是两种实际用例:
1.分离应用程序和第三方库入口,vue-cli中是这样做的:
- const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
webpack 从 app.js 和 vendors.js 开始创建依赖图。这些依赖图是彼此完全分离、互相独立的。这种方式比较常见于,只有一个入口起点(不包括 vendor)的单页应用程序(single page application)中。
2.多页面应用程序
- const config = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};
在多页应用中,页面跳转时服务器将为你获取一个新的 HTML 文档。页面重新加载新文档,并且资源被重新下载。由于入口起点增多,多页应用能够复用入口起点之间的大量代码/模块.
输出(Output)
该属性设置 webpack 在输出它所创建的 bundles的路径以及命名。
注意: 即使可以存在多个入口起点,但只指定一个输出配置。
用法:
在 webpack 中配置 output 属性的最低要求是,将它的值设置为一个对象,包括以下两点:
filename 用于输出文件的文件名。
目标输出目录 path 的绝对路径。
- const config = {
output: {
filename: 'bundle.js',
path: '/home/proj/public/assets'
}
};
module.exports = config;
此配置将一个单独的 bundle.js 文件输出到 /home/proj/public/assets 目录中。
多个入口时:
如果配置创建了多个单独的 "chunk"(例如,使用多个入口起点或使用像 CommonsChunkPlugin 这样的插件),则应该使用占位符(substitutions)来确保每个文件具有唯一的名称。
- {
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
}
复杂示例:
以下是使用 CDN 和资源 hash 的复杂示例
- output: {
path: "/home/proj/cdn/assets/[hash]",
publicPath: "http://cdn.example.com/assets/[hash]/"
}
在编译时不知道最终输出文件的 publicPath 的情况下,publicPath 可以留空,并且在入口起点文件运行时动态设置。如果你在编译时不知道 publicPath,你可以先忽略它,并且在入口起点设置 __webpack_public_path__。
- __webpack_public_path__ = myRuntimePublicPath
// 剩余的应用程序入口
loader
用于对模块的源代码进行转换。loader 可以使你在 import 或"加载"模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!
示例:
使用loader加载 CSS 文件 和 将 TypeScript 转为 JavaScript。
首先安装对应的loader
- npm install --save-dev css-loader
- npm install --save-dev ts-loader
然后指示 webpack 对每个 .css 使用 css-loader,以及对所有 .ts 文件使用 ts-loader:
- module.exports = {
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.ts$/, use: 'ts-loader' }
]
}
};
以上配置,对一个 module 对象定义了 rules 属性,里面包含两个必须属性:test 和 use。
test 属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件。
use 属性,表示进行转换时,应该使用哪个 loader。
上面的配置代表, 当webpack编译器解析时, 遇到 require()/import 语句有'.css'路径时,在打包之前先用 css-loader 转换一下;遇到 require()/import 语句有'.ts'路径时,在打包之前先用 ts-loader 转换一下
使用Loader的三种方式:
1.配置: 在 webpack.config.js 文件中指定 loader。
module.rules 允许你在 webpack 配置中指定多个 loader。 这是展示 loader 的一种简明方式,并且有助于使代码变得简洁。同时让你对各个 loader 有个全局概览:
- module: {
- rules: [
- {
- test: /\.css$/,
- use: [
- { loader: 'style-loader' },
- {
- loader: 'css-loader',
- options: {
- modules: true
- }
- }
- ]
- }
- ]
- }
2.内联: 在 import 语句或任何等效于 "import" 的方式中指定 loader。
使用 ! 将资源中的 loader 分开。分开的每个部分都相对于当前目录解析。
- import Styles from 'style-loader!css-loader?modules!./styles.css';
通过前置所有规则及使用 !,可以对应覆盖到配置中的任意 loader。选项可以传递查询参数,例如 ?key=value&foo=bar,或者一个 JSON 对象,例如 ?{"key":"value","foo":"bar"}。
3.通过 CLI 使用 loader:
- webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
loader 通过(loader)预处理函数,为 JavaScript 生态系统提供了更多能力。 用户现在可以更加灵活地引入细粒度逻辑,例如压缩、打包、语言翻译等loader 遵循标准的模块解析。多数情况下,loader 将从模块路径(通常将模块路径认为是 npm install, node_modules)解析。loader 模块需要导出为一个函数,并且使用 Node.js 兼容的 JavaScript 编写。通常使用 npm 进行管理,但是也可以将自定义 loader 作为应用程序中的文件。按照约定,loader 通常被命名为 xxx-loader(例如 json-loader)。
用法:
由于插件可以携带参数/选项,你必须在 webpack 配置中,向 plugins 属性传入 new 实例。
根据你的 webpack 用法,这里有多种方式使用插件。
- const HtmlWebpackPlugin = require('html-webpack-plugin'); //通过 npm 安装
- const webpack = require('webpack'); //访问内置的插件
- const path = require('path');
- const config = {
- entry: './path/to/my/entry/file.js',
- output: {
- filename: 'my-first-webpack.bundle.js',
- path: path.resolve(__dirname, 'dist')
- },
- module: {
- loaders: [
- {
- test: /\.(js|jsx)$/,
- use: 'babel-loader'
- }
- ]
- },
- plugins: [
- new webpack.optimize.UglifyJsPlugin(),
- new HtmlWebpackPlugin({template: './src/index.html'})
- ]
- };
- module.exports = config;
插件(plugins)
loader 被用于转换某些类型的模块,而插件的使用范围包括,从打包优化和压缩,一直到重新定义环境中的变量。可以用来处理各种任务.
使用某个插件,只需要require(),然后添加到 plugins 数组中.多数插件可以通过选项(option)自定义,也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建它的一个实例。
示例:
- const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
- const webpack = require('webpack'); // 用于访问内置插件
- const path = require('path');
- const config = {
- entry: './src/main.js',
- output: {
- path: path.resolve(__dirname, 'dist'), //生成文件(emit)的路径
- filename: 'yq-webpack.bundle.js' // webpack bundle 的名称
- },
- module: {
- rules: [
- {test: /\.txt$/, use: 'raw-loader'}
- ]
- },
- plugins: [
- new webpack.optimize.UglifyJsPlugin(),
- new HtmlWebpackPlugin({template: './src/index.html'})
- ]
- };
- module.exports = config;
模块
在模块化编程中,开发者将程序分解成离散功能块(discrete chunks of functionality),并称之为_模块_。
每个模块具有比完整程序更小的接触面,使得校验、调试、测试轻而易举。 精心编写的_模块_提供了可靠的抽象和封装界限,使得应用程序中每个模块都具有条理清楚的设计和明确的目的。
对比 Node.js 模块,webpack _模块_能够以各种方式表达它们的依赖关系
- ES2015 import 语句
- CommonJS require() 语句
- AMD define 和 require 语句
- css/sass/less 文件中的 @import 语句。
- 样式(url(...))或 HTML 文件(<img src=...>)中的图片链接(image url)
resolver 是一个库(library),用于帮助找到模块的绝对路径。一个模块可以作为另一个模块的依赖模块,然后被后者引用,如下:
- import foo from 'path/to/module'
- // 或者
- require('path/to/module')
所依赖的模块可以是来自应用程序代码或第三方的库(library)。resolver 帮助 webpack 找到 bundle 中需要引入的模块代码,这些代码在包含在每个 require/import 语句中。 当打包模块时,webpack 使用 enhanced-resolve 来解析文件路径
webpack 中的解析规则
webpack 能够解析三种文件路径:
绝对路径:
- import "/home/me/file";
- import "C:\\Users\\me\\file";
相对路径
- import "/home/me/file";
- import "C:\\Users\\me\\file";
在这种情况下,使用 import 或 require 的资源文件(resource file)所在的目录被认为是上下文目录(context directory)。在 import/require 中给定的相对路径,会添加此上下文路径(context path),以产生模块的绝对路径(absolute path)。
模块路径
- import "module";
- import "module/lib/file";
模块将在 resolve.modules 中指定的所有目录内搜索。
- 一旦根据上述规则解析路径后,解析器(resolver)将检查路径是否指向文件或目录。如果路径指向一个文件:
- 如果路径具有文件扩展名,则被直接将文件打包。
- 否则,将使用 [resolve.extensions] 选项作为文件扩展名来解析,此选项告诉解析器在解析中能够接受哪些扩展名(例如 .js, .jsx)。
如果路径指向一个文件夹,则采取以下步骤找到具有正确扩展名的正确文件:
- 如果文件夹中包含 package.json 文件,则按照顺序查找 resolve.mainFields 配置选项中指定的字段。并且 package.json 中的第一个这样的字段确定文件路径。
- 如果 package.json 文件不存在或者 package.json 文件中的 main 字段没有返回一个有效路径,则按照顺序查找 resolve.mainFiles 配置选项中指定的文件名,看是否能在 import/require 目录下匹配到一个存在的文件名。
- 文件扩展名通过 resolve.extensions 选项采用类似的方法进行解析。
- webpack 根据构建目标(build target)为这些选项提供了合理的默认配置。
通过核心概念了解webpack工作机制的更多相关文章
- Elasticsearch学习笔记(六)核心概念和分片shard机制
一.核心概念 1.近实时(Near Realtime NRT) (1)从写入数据到数据可以被搜索到有一个小延迟(大概1秒): (2)基于es执行搜索和分析可以达到秒级 2.集群(Cluster) 一个 ...
- Hadoop MapReduce 一文详解MapReduce及工作机制
@ 目录 前言-MR概述 1.Hadoop MapReduce设计思想及优缺点 设计思想 优点: 缺点: 2. Hadoop MapReduce核心思想 3.MapReduce工作机制 剖析MapRe ...
- Elasticsearch之重要核心概念(cluster(集群)、shards(分配)、replicas(索引副本)、recovery(据恢复或叫数据重新分布)、gateway(es索引的持久化存储方式)、discovery.zen(es的自动发现节点机制机制)、Transport(内部节点或集群与客户端的交互方式)、settings(修改索引库默认配置)和mappings)
Elasticsearch之重要核心概念如下: 1.cluster 代表一个集群,集群中有多个节点,其中有一个为主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的.es的一个概念就是 ...
- webpack安装与核心概念
安装webpack webpack核心概念:入口.输出.加载器.插件.模块.模式 一.安装webpack 1.安装webpack之前需要安装nodejs环境,在使用nodejs环境自带的包管理工具np ...
- WebGPU 导入[2] - 核心概念与重要机制解读
目录 1. 核心概念 ① 适配器和设备 ② 缓冲.纹理.采样器 ③ 绑定组 ④ 着色器与管线 ⑤ 编码器与队列 2. 重要机制 ① 缓冲映射机制 ② 时间线 1. 核心概念 这部分不会详细展开,以后写 ...
- webpack的四个核心概念介绍
前言 webpack 是一个当下最流行的前端资源的模块打包器.当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后 ...
- webpack核心概念
一.webpack四个核心概念 1.入口[Entry] webpack将创建所有应用程序 依赖关系图表.图表的起点被称之为 入口起点.入口起点告诉webpack从哪里开始,并遵循着依赖关系图表知道打包 ...
- RabbitMQ如何工作和RabbitMQ核心概念
RabbitMQ是一个开源的消息代理软件.它接受来自生产者的消息并将其传递给消费者.它就像一个中间人,可以用来减少Web应用程序服务器的负载和交付时间. RabbitMQ如何工作 让我们简要介绍一下R ...
- hibernate学习系列-----(2)hibernate核心接口和工作机制
在上一篇文章hibernate学习系列-----(1)开发环境搭建中,大致总结了hibernate的开发环境的搭建步骤,今天,我们继续了解有关hibernate的知识,先说说这篇文章的主要内容吧: C ...
随机推荐
- Hibernate 的原生 SQL 查询
Hibernate除了支持HQL查询外,还支持原生SQL查询. 对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQuery()获取 ...
- MySQL 查询最近几天的记录 最近7天的记录 本周内的记录
本周内:select * from wap_content where week(created_at) = week(now) 查询一天:select * from table where to_d ...
- Linuxc - 多c文件程序编译执行
多文件使用,一起编译 定义max.h int max(int a,int b); 定义max.c #include "max.h" int max(int a,int b) { i ...
- 解决svn--Unable to connect to a repository at URL ‘https://xxxxxx’ 问题
在checkout项目时,出现如下错误: Error Unable to connect to a repository at URL 'https://XXXX' Error Access to ...
- 实现iota函数
void Reverse(char *s) { char temp; char *p = s; char *q = s; while (*p != '\0') { p ++; } q --; whil ...
- TOMCAT原理详解及请求过程
Tomcat: Tomcat是一个JSP/Servlet容器.其作为Servlet容器,有三种工作模式:独立的Servlet容器.进程内的Servlet容器和进程外的Servlet容器. Tomcat ...
- XML系列之--Linq操作带属性的XML(四)
关于XML,之前解析过电文收发方面的,就是所谓的带表头.前缀(命名空间)SOAP格式.这次需求是解析一个xml的模板(xls内容),然后填充数据,最后保存.需要时可转换xls.pdf等文件.关于这种带 ...
- docker之NGINX镜像构建
Nginx是一个高性能的Web和反向代理服务器,它具有很多非常优越的特性:1.作为Web服务器.2.作为负载均衡服务器.3.作为邮件代理服务器.4.安装及配置简单.接下来我们介绍在docker构建ng ...
- 知识点干货—多线程同步【6】之synchronized
"明日复明日,明日何其多. 我生待明日,万事成蹉跎. 世人若被明日累,春去秋来老将至. 朝看水东流,暮看日西坠. 百年明日能几何?请君听我明日歌. 明日复明日,明日何其多! 日日待明日,万世 ...
- PHP 第3方评论系统
这段时间,无觅 评论也下线不能使用了. 客户好几个网站使用了.无觅 评论,前面也是用的是多说还是什么,总之也是第3方评论,没想到没过多久,又停止使用了. 没办法,网站还是需要评论系统,一气之下,自己做 ...