Webpack初步接触(一)

官网v3.5.5

1. 简介

一个大现代js应用程序的模块打包工具(module bundler)。webpack可以纯粹在服务端运行。
当webpack处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要地每个模块,然后将所有地这些模块打包成少量的bundle,通常只有一个,由浏览器加载。它是高度可配置的。

2.概念

1)入口entry

webpack创建应用程序所有依赖的关系图。图的起点被称为入口起点(entry point)。
入口起点告诉webpack从哪里开始,并根据依赖关系图确定需要打包的内容。可以将应用程序的入口起点认为是根上下文或app第一个启动文件。
在webpack配置对象中,我们使用entry属性来定义入口

module.exports={
 entry: './path/to/entry/file.js'
}

2)输出Output

将所有的资源归拢到一起后,还需要告诉webpack在哪里打包应用程序。webpack的output属性描述了如何处理归拢在一起的代码(bundle code)

const path= require('path');
module.exports={
 entry:'./path/to/my/file.js',
 output:{
  path: path.resolve(__dirname,'dist'),
  filename: 'my-first-webpack.bundle.js'
 }
}

以上代码,我门店通过output.filenameoutput.path属性,告诉webpack bundle的名称,以及我们想要生成(emit)到哪里。

oustput属性除了这两个属性还有更多的属性。

3)加载器Loader

loader在文件被添加到依赖时将文件转为模块。webpack的目标时让webpack聚焦于项目中的所有资源(asset),webpack把每个文件(.css,.html,.scss,.jpg等)都作模块处理,而webpack自身只理解js

loader的两个目标:
(1)识别出应该被对应的loader进行转换的那些文件。(test属性)
(2)转换这些文件,使其能够被添加到依赖图中(并且最终添加到bundle中)。(use属性)

const path= require('path');

const config={
 entry:'./path/to/file.js',
 putput: {
  path: path.resolve(__dirname,'dist');
  filename:'my-first-bundle.js'
 },
 module:{
  rules:[
   { test: /\.txt$/,use:'raw-loader'}
  ]
 }
}
module.exports=config;

以上对一个单独的module对象定义了rules属性,包含两个必须的属性:test,use。这告诉webpack编译器compiler如下信息,当在reqquire()/import语句中被解析为.txt的路径时,你在对它打包前用raw-loader转换一下。
必须要明确的是,在webpack中定义loader时,要定义在module.rules中,而不是rules

4)插件entry

想要使用一个插件,require(),然后添加到plugins数组中。多数插件可以通过选项opstion自定义,如果因多次不同的目的而多次使用同一个插件,这时需要通过使用new创建实例。

const HtmlWebpackPugin = require('html-weebpack-plugin');
const webpack = require('webpack'); 
const path = require('path');

const config = {
 entry: './path/myfile.js',
 output:{
  path: path.resolve(__dirname,'dist'),
  filename: 'my-fisr-budle.js'
 },
 module:{
  rules:[
   { test:/\.txt$/, use: 'raw-loader' }
  ]
 },
 plugins:[
  new webpack.optimize.UglifyJsPlugin(),
  new HtmlWebpackPlugin({ template:'./src/index.html'})
 ]
}

module.exports= config;

插件列表
插件了解更多

5)配置

webpack配置是标准的Nodes.js CommonJS模块,你可以做到以下事情:
- 通过require()导入其他文件
- 通过require()使用npm的工具函数
- 使用js控制流表达式,例如 ?:操作符
- 编写并执行函数来生成部分配置
- 对常用值使用常量或变量
虽然技术上可行,但是应该避免以下做法
(1)在使用命令行接口(CLI)时(应该编写自己的命令行接口CLI,或使用 k–env),访问命令行接口参数。
(2)导出不确定值。(调用webpack两次应该产生同样的输出文件)
(3)编写很长的配置(应该将配置拆分为多个文件)

最简单的配置

var path = require('path');

module.exports = {
  entry: './foo.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'foo.bundle.js'
  }
};

webpack 接受以多种编程和数据语言编写的配置文件。

6)模块Modules

webpack将模块化应用于任何文件。每个模块具有比完整程序更小的接触面,使得校验、调试、测试轻而易举。

什么是webpack模块

webpack可以以各种方式表达它们之间的依赖关系,几个例子如下:
es6import语句;
CommonJSrequire()语句;
AMD的definerequire语句;
css/sass/less文件中的@import语句;
样式(url(...))或HTML文件(<img src=...>)中的图片链接、
webpack 1 需要特定的 loader 来转换 ES 2015 import,然而通过 webpack 2 可以开箱即用。

支持的模块类型

loader是什么呢?loader描述了webpack如何处理非js模块。webpack社区为各种流行语言和语言处理器构建了loader。包括:
CoffeeScript
TypeScript
ESNext (Babel)
Sass
Less
Stylus

loader列表。我们的也可以自己编写loader

7)模块解析Module Resolution

resolver是一个库,用于帮助模块找到绝对路径。所依赖的模块可以是应用程序的代码或者第三方库。resolver帮webpack找到bundle中需要引用的模块代码,这些代码包含在每个require/import语句中。webpack使用enhanced-resolve来解析文件路径。

webpack中的解析规则

使用enhanced-resolve,wepack可以解析三种文件路径:
(1)绝对路径
(2)相对路径
(3)模块路径

//绝对路径
import "/home/me/file"
import "c:\\user\\me\\file"
//相对路径
import "../src/file1";
import "./files2"
//模块路径
import "module";
import "module/lib/file";

一旦根据上述规则解析路径后,解析器将检查路径是否指向文件或目录。如果路径指向一个文件:
- 如果文件具有扩展名,则直接将文件打包。
- 否则,将使用【resolve.extensions】选项作为文件扩展名来解析,此选项告诉解析器在解析中能够接收哪些扩展名。(比如.js,.jsx)
- 如果文件夹中包含package.json文件,则按照顺序查找resolve.mainFields配置选项中指定的字段。并且package.json中的第一个这样的字段确定文件路径。

8)依赖图表Dependency Graph

任何时候,一个文件依赖另一个文件,webpack就把此视为文件之间有依赖关系。这使得webpack可以接收任何非代码资源(non-code asset)。
wepack从命令行或配置文件中定义的一个模块列表开始,处理你的应用程序。从这些入口起点开始,webpack递归地构建一个依赖图,这个依赖图包含你需要的每个模块,然后所有的模块打包为少量的bundle,通常只有一个-可由浏览器加载

9)文件清单Manifest

使用wepack构建的应用程序或站点中,有三种主要的代码类型:
1.你或你的团队编写的源码;
2.你的源码会依赖的任何第三方的library或vendor代码
3.webpack的runtime和manifest,管理所有模块的交互

Runtime

runtime以及伴随的manifest数据,主要是指:在浏览器运行时,webpack用来连接模块化的应用程序的所有代码。runtime包含:在模块交互时,连接模块所需的加载和解析逻辑。包含浏览器中的已加载模块的连接,以及懒加载模块的执行逻辑。

Manifest

一旦你的应用程序中,形如index.html文件、一些bundle和各种资源加载到浏览器中,会发生什么呢?你精心安排的/src目录的文件结构已经不在,webpack如何管理所有模块之间的交互?这就是manifest数据用途的来源……
当编译器(compiler)开始执行时、解析和映射应用程序时,它会保留所有模块的详细要点,这个数据集合称为Manifest。
当完成打包并发送到浏览器时,会在运行时通过Manifest来解析和加载模块。无论你选择哪种模块语法,你那些import 或require现在已经转为webpack_require方法,此方法指向模块标识符。通过使用manifest中的数据,runtime将能够查询模块标识符,检索出背后对应的模块

10)构建目标Targets

单个target

什么是target?target就是webpack用于加载块(chunk)的环境
要在webpack配置文件(webpack.config.js)中设置target属性

module.exports={
 target:'node'
};

上面的例子中,使用node,webpack会编译为用于【类Node.js】环境。(使用Node.js的require,而不是使用任意内置模块(如fs,或path),来加载chunk)
target可用值

多个target

webpacck不支持向target传入多个字符串,但是,你可以通过打包两份分离的配置来创建同构的库。

var path=require('path');
var serveConfig={
 target:'node',
 output:{
  path:path.resolve(__dirname,'dist');
  filename:'lib.node.js'
 }
 //......
};
//第二个配置
var clientConfig={
 target: 'web',
 output:{
  path: path.resolve(__dirname,'dist');
  filename: 'lib.js'
 }
 //......
}

module.exports=[serverConfig,clientConfig];

11)模块热替换Hot Module Replacement

模块热替换功能会在应用程序运行过程中替换、添加或删除模块,而无须重新加载整个页面。
- 保留在完全重新加载页面时丢失的应用程序状态;
- 只更新变更内容,以节省宝贵的开发时间;
- 调整样式更加快速-几乎等于在浏览器调试器中更改样式。

HMR的工作原理

在应用程序中

1.应用程序代码要求HMR检测更新;
2.HMR runtime(异步)下载更新,然后通知应用程序代码;
3.应用程序代码要求HMR runtime应用更新;
4.HMR runtime(异步)应用更新。
你可以设置HMR,以使此进程自动触发更新,或者你可以选择要求在用户交互时进行更新。

在编译器中

除了普通资源(什么是普通资源?暂时不清楚),编译器需要发出’update’,以允许更新之前的模板到新的版本。’update’由两部分组成:
1.更新后的manifest(JSON);
2.一个或多个更新后的chunk(js)。
manifest包括新的编译hash和所有的待更新chunk目录。每个更新chunk都含有应用于此chunk的全部更新模块的代码或一个flag用于表明此模块要被移除。
所以,chunk是一些模块的集合
编译器确保模块ID和chunk ID在这些构建之间保持一致。通常将这些ID存储在内存中(例如使用webpack-dev-server时),也可能存储在JSON文件中。

在模块中

HMR是可选功能,只影响包含HMR代码的模块。举个例子,通过style-loader为style样式追加补丁。为了运行追加补丁,style-loader实现了HMR接口;当它通过HMR接收到更新,它会使用新的样式替换旧的样式。
然而在多数情况下,不需要强制在每个模块中写入HMR代码,如果一个模块没有HMR处理处理函数,更新就会冒泡。这意味着一个简单的处理函数能够对整个模块树进行更新;如果在这个模块树中,一个单独的模块树被更新,那么整组依赖模块都会被重新加载。
module.hot接口的详细信息,HMR API
webpack强大之处在于它的可定制化。更多细节可以看模块热更新指南

猜你喜欢

转载自blog.csdn.net/e_li_na/article/details/80305739