.15-浅析webpack源码之WebpackOptionsApply模块之插件王中王

  总体过了一下后面的流程,发现Compiler模块确实不适合单独讲解,这里继续讲解后面的代码:

compiler.options = new WebpackOptionsApply().process(options, compiler);

  这行代码与之前设置options默认值非常相似,但是复杂程度根本不是一个次元的。

  这一节只能简单的看一眼内部到底有多少东西,整理后源码如下:

"use strict";

const OptionsApply = require("./OptionsApply");
// ...巨量插件引入

class WebpackOptionsApply extends OptionsApply {
    constructor() {
        super();
    }
    process(options, compiler) {
        let ExternalsPlugin;
        compiler.outputPath = options.output.path;
        compiler.recordsInputPath = options.recordsInputPath || options.recordsPath;
        compiler.recordsOutputPath = options.recordsOutputPath || options.recordsPath;
        compiler.name = options.name;
        compiler.dependencies = options.dependencies;
        // 在默认参数配置中被设置为web
        if (typeof options.target === "string") {
            let JsonpTemplatePlugin;
            let NodeSourcePlugin;
            let NodeTargetPlugin;
            let NodeTemplatePlugin;
            switch (options.target) {
                case "web":
                    JsonpTemplatePlugin = require("./JsonpTemplatePlugin");
                    NodeSourcePlugin = require("./node/NodeSourcePlugin");
                    compiler.apply(
                        new JsonpTemplatePlugin(options.output),
                        new FunctionModulePlugin(options.output),
                        new NodeSourcePlugin(options.node),
                        new LoaderTargetPlugin(options.target)
                    );
                    break;
                    // other case...
                default:
                    throw new Error("Unsupported target ‘" + options.target + "‘.");
            }
        } else if (options.target !== false) {
            options.target(compiler);
        } else {
            throw new Error("Unsupported target ‘" + options.target + "‘.");
        }
        // options.output.library参数处理
        if (options.output.library || options.output.libraryTarget !== "var") { /**/ }
        // options.output.externals参数处理
        if (options.externals) { /**/ }
        let noSources;
        let legacy;
        let modern;
        let comment;
        // options.devtool => sourcemap || source-map
        if (options.devtool && (options.devtool.indexOf("sourcemap") >= 0 || options.devtool.indexOf("source-map") >= 0)) { /**/ }
        // options.devtool => sourcemap || source-map
        else if (options.devtool && options.devtool.indexOf("eval") >= 0) { /**/ }
        // 加载模块并触发entry-option事件流
        compiler.apply(new EntryOptionPlugin());
        compiler.applyPluginsBailResult("entry-option", options.context, options.entry);
        // 疯狂加载插件
        compiler.apply( /**/ );
        // options.performance参数处理
        if (options.performance) { /**/ }

        // 继续加载插件
        compiler.apply(new TemplatedPathPlugin());
        compiler.apply(new RecordIdsPlugin());
        compiler.apply(new WarnCaseSensitiveModulesPlugin());
        // options.performance参数处理
        if (options.cache) { /**/ }
        // 触发after-plugins
        compiler.applyPlugins("after-plugins", compiler);
        if (!compiler.inputFileSystem) throw new Error("No input filesystem provided");
        // 给compiler.resolvers设置值
        compiler.resolvers.normal = ResolverFactory.createResolver(Object.assign({
            fileSystem: compiler.inputFileSystem
        }, options.resolve));
        compiler.resolvers.context = ResolverFactory.createResolver(Object.assign({
            fileSystem: compiler.inputFileSystem,
            resolveToContext: true
        }, options.resolve));
        compiler.resolvers.loader = ResolverFactory.createResolver(Object.assign({
            fileSystem: compiler.inputFileSystem
        }, options.resolveLoader));
        // 触发after-resolvers事件流
        compiler.applyPlugins("after-resolvers", compiler);
        return options;
    }
}

module.exports = WebpackOptionsApply;

  这个模块除去父类引入,其余插件光顶部引入就有34个,简直就是插件之王。

  略去具体插件内容,先看流程,父类其实是个接口,啥都没有:

"use strict";

class OptionsApply {
    process(options, compiler) {}
}
module.exports = OptionsApply;

  接下来是一个唯一的主方法process,总结下流程依次为:

1、根据options.target加载对应的插件,如果配置文件没有配置该参数,则在WebpackOptionsDefaulter模块会被自动初始化为web。

2、处理options.output.library、options.output.externals参数

3、处理options.devtool参数

4、加载EntryOptionPlugin插件并触发entry-option的事件流

5、加载大量插件

6、处理options.performance参数

7、加载TemplatePathPlugin、RecordIdPlugin、WarnCaseSensitiveModulesPlugin插件

8、触发after-plugins事件流

9、设置compiler.resolvers的值

10、触发after-resolvers事件流

  如果按类型分,其实只有两种:加载插件,触发事件流。

  事件流的触发类似于vue源码里的钩子函数,到特定的阶段触发对应的方法,这个思想在Java的数据结构源码中也被普通应用。

  模块中的参数处理如果该参数比较常用,那么就进行分析,其余不太常用的就先跳过,按顺序依次讲解。

  这里的options经过默认参数模块的加工,丰富后如下:

{
    "entry": "./input.js",
    "output": {
        "filename": "output.js",
        "chunkFilename": "[id].output.js",
        "library": "",
        "hotUpdateFunction": "webpackHotUpdate",
        "jsonpFunction": "webpackJsonp",
        "libraryTarget": "var",
        "path": "D:\\workspace\\doc",
        "sourceMapFilename": "[file].map[query]",
        "hotUpdateChunkFilename": "[id].[hash].hot-update.js",
        "hotUpdateMainFilename": "[hash].hot-update.json",
        "crossOriginLoading": false,
        "chunkLoadTimeout": 120000,
        "hashFunction": "md5",
        "hashDigest": "hex",
        "hashDigestLength": 20,
        "devtoolLineToLine": false,
        "strictModuleExceptionHandling": false
    },
    "context": "D:\\workspace\\doc",
    "devtool": false,
    "cache": true,
    "target": "web",
    "module": {
        "unknownContextRequest": ".",
        "unknownContextRegExp": false,
        "unknownContextRecursive": true,
        "unknownContextCritical": true,
        "exprContextRequest": ".",
        "exprContextRegExp": false,
        "exprContextRecursive": true,
        "exprContextCritical": true,
        "wrappedContextRegExp": {},
        "wrappedContextRecursive": true,
        "wrappedContextCritical": false,
        "strictExportPresence": false,
        "strictThisContextOnImports": false,
        "unsafeCache": true
    },
    "node": {
        "console": false,
        "process": true,
        "global": true,
        "Buffer": true,
        "setImmediate": true,
        "__filename": "mock",
        "__dirname": "mock"
    },
    "performance": {
        "maxAssetSize": 250000,
        "maxEntrypointSize": 250000,
        "hints": false
    },
    "resolve": {
        "unsafeCache": true,
        "modules": ["node_modules"],
        "extensions": [".js", ".json"],
        "mainFiles": ["index"],
        "aliasFields": ["browser"],
        "mainFields": ["browser", "module", "main"],
        "cacheWithContext": false
    },
    "resolveLoader": {
        "unsafeCache": true,
        "mainFields": ["loader", "main"],
        "extensions": [".js", ".json"],
        "mainFiles": ["index"],
        "cacheWithContext": false
    }
}

  除去entry与output.filename,其余的参数全部是填充上去的,因为后面的流程会检测参数,所以这里先列出来。

  这一节先这样,具体内容后面进行详细讲解。

时间: 2024-10-28 23:12:15

.15-浅析webpack源码之WebpackOptionsApply模块之插件王中王的相关文章

.10-浅析webpack源码之graceful-fs模块

在cachedInput.output.watch三大文件系统中,output非常简单,没有必要讲,其余两个模块依赖于input模块,而input主要是引用了graceful-fs的部分API,所以这节来讲讲graceful-fs. 上一节整理的源码如下: var fs = require('fs') // ...工具方法 module.exports = patch(require('./fs.js')) if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATC

.11-浅析webpack源码之Storage模块

至此已完成NodeJsInputFileSysten模块的讲解,下一步就是实际实用的模块: compiler.inputFileSystem = new CachedInputFileSystem(new NodeJsInputFileSystem(), 60000); 挂载到compiler对象上的输入模块其实是带有缓存的输入模块,源码整理如下(用ES6的class重写): class CachedInputFileSystem { constructor() { // fileSystem

.12-浅析webpack源码之NodeWatchFileSystem模块总览

剩下一个watch模块,这个模块比较深,先大概过一下整体涉及内容再分部讲解. 流程图如下: NodeWatchFileSystem const Watchpack = require("watchpack"); class NodeWatchFileSystem { constructor(inputFileSystem) { this.inputFileSystem = inputFileSystem; this.watcherOptions = { aggregateTimeout

分享15个美化源码的代码语法着色器

语法高亮是文本编辑器用来显示文本的,特别是源代码,根据不同的类别来用不同的颜色和字体显示.这个功能有助于编写结构化的语言,比如编程语言,标记语言,这些语言的语法错误显示是有区别的.语法高亮并不会影响文本自身的意义,而且能很好的符合人们的阅读习惯. 语法高亮同时也能帮助开发者很快的找到他们程序中的错误.例如,大部分编辑器会用不同的颜色突出字符串常量.所以,非常容易发现是否遗漏了分隔符,因为相对于其他文本颜色不同. 现在有各种各样的语法高亮工具,可以格式化语言,并且根据不同的编程语言进行高亮显示.无

nginx源码分析之模块初始化

在nginx启动过程中,模块的初始化是整个启动过程中的重要部分,而且了解了模块初始化的过程对应后面具体分析各个模块会有事半功倍的效果.在我看来,分析源码来了解模块的初始化是最直接不过的了,所以下面主要通过结合源码来分析模块的初始化过程. 稍微了解nginx的人都知道nginx是高度模块化的,各个功能都封装在模块中,而各个模块的初始化则是根据配置文件来进行的,下面我们会看到nginx边解析配置文件中的指令,边初始化指令所属的模块,指令其实就是指示怎样初始化模块的. 模块初始化框架 模块的初始化主要

区块链教程btcpool矿池源码分析StratumServer模块解析

兄弟连区块链教程btcpool矿池源码分析StratumServer模块解析 核心机制总结 接收的job延迟超过60秒将丢弃 如果job中prevHash与本地job中prevHash不同,即为已产生新块,job中isClean状态将置为true????* true即要求矿机立即切换job 三种情况下将向矿机下发新job:???? 收到新高度的job???? 过去一个job为新高度且为空块job,且最新job为非空块job????* 达到预定的时间间隔30秒 最近一次下发job的时间将写入文件(

webpack源码-依赖收集

webpack源码-依赖收集 version:3.12.0 程序主要流程: 触发make钩子 Compilation.js 执行EntryOptionPlugin 中注册的make钩子 执行compilation.addEntry 执行compilation._addModuleChain Compilation.js 执行moduleFactory.create(this.semaphore.avaiable 初始化为100) Compilation.js 执行this.buildModule

nginx源码分析--nginx模块解析

nginx的模块非常之多,可以认为所有代码都是以模块的形式组织,这包括核心模块和功能模块,针对不同的应用场合,并非所有的功能模块都要被用到,附录A给出的是默认configure(即简单的http服务器应用)下被连接的模块,这里虽说是模块连接,但nginx不会像apache或lighttpd那样在编译时生成so动态库而在程序执行时再进行动态加载,nginx模块源文件会在生成nginx时就直接被编译到其二进制执行文件中,所以如果要选用不同的功能模块,必须对nginx做重新配置和编译.对于功能模块的选

thttpd源码解析 定时器模块

thttpd源码解析 定时器模块 thttpd是非常轻量级的http服务器,可执行文件仅50kB.名称中的第一个t表示tiny, turbo, 或throttling 与lighttpd.memcached.redis相比非常小巧,仅有不到8k行,而后三者大小分别为:60k,13k,86k 支持HTTP/1.1和CGI:采用IO复用实现,单线程,可移植:实现了基于URL的文件流量限制功能 特别适用于大量静态数据访问的场景,如图片存储 2004年已经停止维护,有一个关于X-Forwarded-Fo