通过核心概念了解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 ...
随机推荐
- EL表达式得不到后台传过来的值
两种jsp获得action传过来的值 第一种: <s:iterator value="#pagination.datas" var="supplier" ...
- js的join和split
1,split 将字符串转为数组 第一个参数必须,可以是字符串和正则表达式,表示从该地方开始分割字符串:第二个参数可选,表示返回数组的最大长度. split():把整个字符串塞入一个数组中 spl ...
- Effective Java 第三版——28. 列表优于数组
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- 【转】查询SQLSERVER执行过的SQL记录
--创建时间 QS.creation_time, --查询语句 ), (( THEN DATALENGTH(st.text) ) ) AS statement_text, --执行文本 ST.text ...
- 共轭梯度算法求最小值-scipy
# coding=utf-8 #共轭梯度算法求最小值 import numpy as np from scipy import optimize def f(x, *args): u, v = x a ...
- JavaScript之点赞特效
在很多网站中登录后可以对你说喜欢的文章.图片之类的进行点赞,这个功能效果的实现就是我今天要写的东西.代码不长,但觉得还是很有用的,为 js 给用户交互体验上更加友好.在实现过程中,主要的思路有: 点赞 ...
- c:if true、false都显示
看了半天,最后发现jstl标签库没有引入! <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core ...
- linkin大话面向对象--封装和隐藏
软件开发追求的境界:高内聚,低耦合 高内聚:尽可能把模块的内部数据,功能实现细节隐藏在模块内部独立完成,不允许外部直接干预 低耦合:仅暴露少量的方法给外部使用 到底为什么要对一个雷或者对象实现良好的封 ...
- MySQL中, 如何查询某一天, 某一月, 某一年的数据.
今天 select * from 表名 where to_days(时间字段名) = to_days(now()); 昨天(包括昨天和今天的数据) SELECT * FROM 表名 WHERE TO_ ...
- 【转】shell:date 常用方式
在linux下获取时间字符串 命令 date # 以yyyymmdd格式输出23天之前现在这个时刻的时间 $ date +%Y%m%d –date=’23 days ago’ $ date -u Th ...