webpack是JS应用程序的静态模块打包工具。webpack在处理你的应用时,会递归的构建依赖项,这些依赖项包括你的应用程序所需要的所有模块,然后把这些模块打包到一个或多个bundles中。

一、Entry

entry point是项目的入口文件,告诉webpack从哪个模块开始构建内部依赖。进入入口文件后,webpack会直接或间接的找到其依赖的模块和库。

1、定义入口的方式有多种:

1)简写形式(string | array<string>)

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

上面的写法实际上是下面写法的简写形式

multi-main entry: entry是一个存放文件路径的数组,当你需要将多个依赖文件一起注入并将它们的依赖关系打包成一个chunk时,可以使用这种方式。

2)对象形式({ [entryChunkName]: string|array<string> })

const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
}

2、应用场景

1)分离app和vendor入口

const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
}

这种形式告诉webpack从app.js和vendors.js开始创建分离的相互独立的依赖。这在单页面应用中很常用。这种设置允许你利用CommonsChunkPlugin将应用中任何vendor的引用抽离到vendor bundle. 这样在你的应用程序bundle中就没有vendor代码。

2)多页面应用

const config = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};

这种设置方式告诉webpack我们有3个分离的依赖项。在多页面应用中,服务器需要获取新的HTML文档,页面重新加载新的文档和文件需要重新下载,这样我们就可以使用CommonsChunkPlugin将页面间共享的代码提取打包。

黄金条例:每个HTML文档使用一个入口。

二、Output

output属性告诉webpack打包文件的输出位置和名字。 output是一个对象,一般需要文件名(filename)和输出路径(path);

const path = require('path');

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

1、多入口文件

当你的设置会有多个chunk(比如多个入口文件或者使用类似CommonsChunkPlugin)时使用,但你需要保证每个文件都有唯一的名字。

{
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
}

2、publicPath

当你将应用所需文件存放在CDN或者hash时

output: {
path: "/home/proj/cdn/assets/[hash]",
publicPath: "http://cdn.example.com/assets/[hash]/"
}

如果编译时不确定最终的publicPath,这个值可以设为空白或者不设置,然后在入口文件中使用__webpack_public_path__动态设置。

__webpack_public_path__ = myRuntimePublicPath

// rest of your application entry

三、Loaders

loaders可以帮助webpack处理更多类型的文件,不仅限于javascript(webpack自身只能处理JS)。loaders会将各种类型的文件转化为webpack能处理的合法模块。

1、使用方式

1) 配置文件

const path = require('path');

module.exports = {
entry: './path/file.js',
output:{
path: path.resolve(__dirname,'dist'),
filename:'bundle.js',
},
modules:{
rules: [
{test: /\.txt$/, use: 'raw-loader'},
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
]
}
}

2)inline

import Styles from 'style-loader!css-loader?modules!./styles.css';

options可以通过query参数形式传递,比如?key=value&foo=bar,或者JSON对象形式,比如?{"key":"value","foo":"bar"}

3) CLI

webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'

四、Plugins

plugins可以做更多的事情,可以优化和更小化打包文件,或者定义环境变量。

plugin是一个JS对象,有apply属性。apply属性会被webpack的编译器调用,允许进入整个编译周期。

function ConsoleLogOnBuildWebpackPlugin() {

};

ConsoleLogOnBuildWebpackPlugin.prototype.apply = function(compiler) {
compiler.plugin('run', function(compiler, callback) {
console.log("The webpack build process is starting!!!"); callback();
});
};
 plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]

五、Module Resolution

resolver帮助webpack定位模块位置。依赖模块可能来自应用程序中的代码或者第三方库,resolver可以帮助webpack找到模块代码,这些模块代码通过require/import引入,并被打包到bundle中。

1、resolving rules

1)绝对路径

import "/home/me/file";

import "C:\\Users\\me\\file";

因为已经包含了文件绝对路径,所以不需要其他的resolution。

2)相对路径

import "../src/file1";
import "./file2";

在这种情况下,源文件所在文件夹将作为context directory,然后将这些相对路径加入到context路径中生成模块的绝对路径。

3)Module path

import "module";
import "module/lib/file";

resolve.modules下的所有文件夹都会被搜索。你可以使用resolve.alias创建原始Module 路径的别名。

一旦通过上面的规则解析出了路径,resolve会检查该路径指向的是一个文件还是一个文件夹。

如果是文件:

该路径带有文件扩展名,那么文件直接被打包;否则,使用resolve.extensions解析出文件扩展名。

如果指向的是文件夹:

文件夹包含package.json文件,package.json中出现的第一项resolve.mainFields配置项中的文件决定最终的文件路径。如果文件夹中没有package.json文件,或者main fields中没有返回一个合法的路径,依次匹配resolve.mainFields配置项中指定的文件名,看是否找到匹配的文件路径。至于文件扩展名,仍然使用resolve.extensions来解析。

2、resolving loaders

3、caching

每个文件系统都是被缓存的,因此对一个文件的多个平行或者一系列请求会很快。在watch mode,只有修改过的文件会从缓存中删去。如果watch mode被关闭,那么缓存会在每次编译前清除。

六、Targets

因为JS可以用在服务端和浏览器端,你可以在webpack配置文件中配置部署目标。

1、使用

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

在上面的例子中,使用node,webpack会编译一个类似nodejs的环境。target默认设置为web

2、multiple target

虽然webpack不支持给target传多个字符串,但是可以构建两个独立的配置来创建同构的库

var path = require('path');
var serverConfig = {
target: 'node',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'lib.node.js'
}
//…
}; var clientConfig = {
target: 'web', // <=== can be omitted as default is 'web'
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'lib.js'
}
//…
}; module.exports = [ serverConfig, clientConfig ];

这样会在你的dist文件夹下生成lib.js和lib.node.js两个文件。

https://github.com/TheLarkInn/compare-webpack-target-bundles

七、manifest

基本上在一个基于webpack的应用中,会出现三种类型的code:

  • 应用源代码
  • 第三方库或者源代码依赖的vendor code
  • 联系各个模块的runtime 和 manifest

1、 Runtime

当你的应用在浏览器中运行时,runtime和manifest数据基本上是webpack联系你的模块化应用所需的所有code。它包含你的模块之间交互时,链接各个模块所需要的加载和解析逻辑。这包括了连接已经加载到浏览器中的模块,以及延迟加载的模块。

2、manifest

那么当你的应用以index.html文件在浏览器中运行时,那些bundles和其他的文件是什么样的呢?src目录下你写的代码都没有了,那么webpack是怎么处理modules之间的交互的呢?这就是manifest data用到的地方。。。

当编译器进入,解析并映射你的应用时,会一直关注你的modules。这些数据集合就是manifest,当这些modules bundled并且加载进浏览器时,runtime就会利用manifest来解析和加载modules。不管你用的是什么模块语言,import和require都会变为指向module identifiers的__webpack_require__方法。使用manifest中的数据,runtime可以找到这些identifiers后的module位置。

3、problem

这些内容平时一般都用不到,但是如果你想要使用浏览器缓存优化你的应用性能,就需要知道上面这些概念了。

将bundle文件名哈希表示,你可以告诉浏览器文件内容改变了,缓存已经没用了。但如果你这样做,你会发现,有时候文件内容没变,文件名的哈希表示也会变化。这就是因为runtime和manifest在每次构建时都会改变。

八、Hot Module Replacement

应用程序在运行时不需要重新加载页面,HMR就可以修改,添加和删除modules。这在几个方面加速开发过程:

  • 保存应用在重新加载时会丢失的状态;
  • 只更新改变的内容,节约宝贵的开发时间
  • 更快的调整样式,几乎可以和浏览器开发者模式中调整样式一样快速生效

How it works

1、in the application

1)应用程序要求HMR runtime检查更新

2)runtime异步下载更新并通知应用程序

3)应用程序要求runtime应用更新

4)runtime同步应用更新

设置HMR,上面的步骤就会自动发生处理,或者也可以通过用户的交互来更新

2、in the compiler

除了更新普通的文件,编译器还需要发出更新信号,来允许从旧的版本更新到新的版本。这个更新包括两个部分:

  • 更新后的manifest(JSON)
  • 一个或多个更新后的chunks(JS)

manifest包含新的编译hash和所有更新后的chunks清单。每一个这种chunks包含所有更新过的modules 的新code(或者是一个flag表示module被删除)。

编译器会确保在这些构建中module id和chunk id一致,并将这些ID保存在内存中或者JSON文件中。

3、in a module

HMR只会影响包含HMR code的modules。比如style-loader,它实现了HMR接口,当从HMR接收到更新,会用新的样式替换旧的样式。

同样的,当在一个module实现HMR接口时,你可以根据module是否更新来决定接下来应该做什么。但是,在大多数情况下,不需要强制在每个module中写HMR code。如果一个module没有HMR处理机制,更新会冒泡。这意味着,一个单独的处理器可以更新整个module tree。如果一个单独的module被更新了,那么所有依赖项都会重新加载。

4、in the runtime

对于module system runtime,会有额外的代码来追踪module的parents和children。在管理方面,runtime支持两个方法:check和apply。

check向更新的manifest发送HTTP请求。如果请求失败,表示没有可用更新。如果成功,会对比更新后的chunks清单和当前已加载chunks清单。对于每个已加载chunk,相应的更新chunk会被下载。所有module更新都保存在runtime。当所有更新的chunks被下载下来,并且已经准备应用更新,runtime会把状态调整为ready状态。

apply方法将所有更新modules标志为无效。对于每一个无效module,在module或者他的parents处需要有一个更新处理程序。否则,无效标志会向上冒泡,将Parents也标志为无效。冒泡会持续冒到应用程序的入口或者到达一个有更新处理程序的module。如果从entry point开始冒泡,那么进程失败。

然后所有无效modules通过卸载程序被卸载。当前hash被更新,所有accept handlers被调用。runtime切换回idle状态,一切回归正常。

concepts的更多相关文章

  1. 新书到手 TRANSACTION PROCESSING:CONCEPTS AND TECHNIQUES

    新书到手 TRANSACTION PROCESSING:CONCEPTS AND TECHNIQUES Jim Gray大神的著作 本文版权归作者所有,未经作者同意不得转载.

  2. RS-232, RS-422, RS-485 Serial Communication General Concepts(转载)

    前面转载的几篇文章重点介绍了UART及RS-232.在工控领域除了RS-232以外,常用的串行通信还有RS-485.本文转载的文章重点介绍了RS-232.RS-422和RS-485. Overview ...

  3. Deep Learning in a Nutshell: Core Concepts

    Deep Learning in a Nutshell: Core Concepts This post is the first in a series I’ll be writing for Pa ...

  4. (转) Deep Learning in a Nutshell: Core Concepts

    Deep Learning in a Nutshell: Core Concepts Share:   Posted on November 3, 2015by Tim Dettmers 7 Comm ...

  5. AngularJs学习笔记--concepts(概念)

    原版地址:http://code.angularjs.org/1.0.2/docs/guide/concepts 继续.. 一.总括 本文主要是angular组件(components)的概览,并说明 ...

  6. Part 16 Important concepts related to functions in sql server

    Important concepts related to functions in sql server

  7. Basic Vlan Concepts

    1.  Vlan Benefit ·To reduce CPU overhead on each device by reducing the number of devices that recei ...

  8. Spring Batch Concepts Chapter

    Spring Batch Concepts Chapter The below figure shows two kinds of Spring Batch components:infrastruc ...

  9. Six important .NET concepts 【Turn】

    Introduction This article will explain six important concepts: stack, heap, value types, reference t ...

  10. Learing WCF Chapter1 Fundamental WCF Concepts

    At its core,WCF is a development platform for service-oriented applications. As I mentioned earlier, ...

随机推荐

  1. Intent 传递Map数据

    android开发默认情况下,通过Bundle bundle=new Bundle();传递值是不能直接传递map对象的,解决办法: 第一步:封装自己的map,实现序列化即可 /** *序列化map供 ...

  2. WPF 利用HwndSource拦截Windows消息

    WPF提供了一个HwndSource可以使你更快的实现处理Windows消息. 通过HwndSource.FromHwnd得到的HwndSource可以添加(AddHook)移除(Remove)Hoo ...

  3. php的FTP操作类

    class_ftp.php <?php /** * 作用:FTP操作类( 拷贝.移动.删除文件/创建目录 ) */ class class_ftp { public $off; // 返回操作状 ...

  4. ES6中async和await说明和用法

    昨天看了一篇vue的教程,作者用async/ await来发送异步请求,从服务端获取数据,代码很简洁,同时async/await 已经被标准化,是时候学习一下了. 先说一下async的用法,它作为一个 ...

  5. DOM 事件监听 事件冒泡 事件捕获

    addEventListener() 方法 实例: // 当用户点击按钮时触发监听事件: document.getElementById("myBtn").addEventList ...

  6. SVN 打包时,出现File not found: transaction '148-48', path ''https://xxxxxx/svn/xxxxx/tag/2017-9-30'

    svn打包时,出现错误如下: 解决办法: 在SVN目录结构中,增加tag这个目录.

  7. NYoj 155最短路

    //dij #include<stdio.h> #include<string.h> #include<queue> using namespace std; #d ...

  8. Linux平台的SVN服务器的配置及搭建

    https://jingyan.baidu.com/article/54b6b9c08b35382d593b477c.html 一.安装SVN   1 在Linux平台上,SVN的软件包名称是subv ...

  9. 安装 cx_Oracle

    1.下载 oracle client instant  和  sdk,  全部解压到 /opt/instantclient_11_2/ http://www.oracle.com/technetwor ...

  10. 确定比赛名次 HDU - 1285 (拓扑排序)

     注意点: 输入数据中可能有重复,需要进行处理! #include <stdio.h> #include <iostream> #include <cstring> ...