CommonJsRequireDependencyParserPlugin.js 3.98 KB
Newer Older
liang ce committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

const CommonJsRequireDependency = require("./CommonJsRequireDependency");
const CommonJsRequireContextDependency = require("./CommonJsRequireContextDependency");
const RequireHeaderDependency = require("./RequireHeaderDependency");
const LocalModuleDependency = require("./LocalModuleDependency");
const ContextDependencyHelpers = require("./ContextDependencyHelpers");
const LocalModulesHelpers = require("./LocalModulesHelpers");
const ParserHelpers = require("../ParserHelpers");

class CommonJsRequireDependencyParserPlugin {
	constructor(options) {
		this.options = options;
	}

	apply(parser) {
		const options = this.options;

		const processItem = (expr, param) => {
			if (param.isString()) {
				const dep = new CommonJsRequireDependency(param.string, param.range);
				dep.loc = expr.loc;
				dep.optional = !!parser.scope.inTry;
				parser.state.current.addDependency(dep);
				return true;
			}
		};
		const processContext = (expr, param) => {
			const dep = ContextDependencyHelpers.create(
				CommonJsRequireContextDependency,
				expr.range,
				param,
				expr,
				options,
				{},
				parser
			);
			if (!dep) return;
			dep.loc = expr.loc;
			dep.optional = !!parser.scope.inTry;
			parser.state.current.addDependency(dep);
			return true;
		};

		parser.hooks.expression
			.for("require.cache")
			.tap(
				"CommonJsRequireDependencyParserPlugin",
				ParserHelpers.toConstantDependencyWithWebpackRequire(
					parser,
					"__webpack_require__.c"
				)
			);
		parser.hooks.expression
			.for("require")
			.tap("CommonJsRequireDependencyParserPlugin", expr => {
				const dep = new CommonJsRequireContextDependency(
					{
						request: options.unknownContextRequest,
						recursive: options.unknownContextRecursive,
						regExp: options.unknownContextRegExp,
						mode: "sync"
					},
					expr.range
				);
				dep.critical =
					options.unknownContextCritical &&
					"require function is used in a way in which dependencies cannot be statically extracted";
				dep.loc = expr.loc;
				dep.optional = !!parser.scope.inTry;
				parser.state.current.addDependency(dep);
				return true;
			});

		const createHandler = callNew => expr => {
			if (expr.arguments.length !== 1) return;
			let localModule;
			const param = parser.evaluateExpression(expr.arguments[0]);
			if (param.isConditional()) {
				let isExpression = false;
				const prevLength = parser.state.current.dependencies.length;
				const dep = new RequireHeaderDependency(expr.callee.range);
				dep.loc = expr.loc;
				parser.state.current.addDependency(dep);
				for (const p of param.options) {
					const result = processItem(expr, p);
					if (result === undefined) {
						isExpression = true;
					}
				}
				if (isExpression) {
					parser.state.current.dependencies.length = prevLength;
				} else {
					return true;
				}
			}
			if (
				param.isString() &&
				(localModule = LocalModulesHelpers.getLocalModule(
					parser.state,
					param.string
				))
			) {
				const dep = new LocalModuleDependency(localModule, expr.range, callNew);
				dep.loc = expr.loc;
				parser.state.current.addDependency(dep);
				return true;
			} else {
				const result = processItem(expr, param);
				if (result === undefined) {
					processContext(expr, param);
				} else {
					const dep = new RequireHeaderDependency(expr.callee.range);
					dep.loc = expr.loc;
					parser.state.current.addDependency(dep);
				}
				return true;
			}
		};
		parser.hooks.call
			.for("require")
			.tap("CommonJsRequireDependencyParserPlugin", createHandler(false));
		parser.hooks.new
			.for("require")
			.tap("CommonJsRequireDependencyParserPlugin", createHandler(true));
		parser.hooks.call
			.for("module.require")
			.tap("CommonJsRequireDependencyParserPlugin", createHandler(false));
		parser.hooks.new
			.for("module.require")
			.tap("CommonJsRequireDependencyParserPlugin", createHandler(true));
	}
}
module.exports = CommonJsRequireDependencyParserPlugin;