TransformDependencyBlockPlugin.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. const DependenciesBlockVariable = require('webpack/lib/DependenciesBlockVariable');
  2. const pluginCompat = require('./util/plugin-compat');
  3. const BlockSchemas3 = [
  4. [
  5. 'AMDRequireDependenciesBlock',
  6. 'expr',
  7. 'arrayRange',
  8. 'functionRange',
  9. 'errorCallbackRange',
  10. 'module',
  11. 'loc',
  12. ],
  13. ['ImportDependenciesBlock', 'request', 'range', 'chunkName', 'module', 'loc'],
  14. [
  15. 'RequireEnsureDependenciesBlock',
  16. 'expr',
  17. 'successExpression',
  18. 'errorExpression',
  19. 'chunkName',
  20. 'chunkNameRange',
  21. 'module',
  22. 'loc',
  23. ],
  24. ['AsyncDependenciesBlock', 'name', 'module'],
  25. ];
  26. const BlockSchemas4 = [
  27. [
  28. 'AMDRequireDependenciesBlock',
  29. 'expr',
  30. 'arrayRange',
  31. 'functionRange',
  32. 'errorCallbackRange',
  33. 'module',
  34. 'loc',
  35. 'request',
  36. ],
  37. [
  38. 'ImportDependenciesBlock',
  39. 'request',
  40. 'range',
  41. 'groupOptions',
  42. 'module',
  43. 'loc',
  44. 'originModule',
  45. ],
  46. [
  47. 'RequireEnsureDependenciesBlock',
  48. 'expr',
  49. 'successExpression',
  50. 'errorExpression',
  51. 'chunkName',
  52. 'chunkNameRange',
  53. 'module',
  54. 'loc',
  55. ],
  56. ['AsyncDependenciesBlock', 'groupOptions', 'module', 'loc', 'request'],
  57. ];
  58. try {
  59. BlockSchemas3[0].DependencyBlock = require('webpack/lib/dependencies/AMDRequireDependenciesBlock');
  60. BlockSchemas4[0].DependencyBlock = require('webpack/lib/dependencies/AMDRequireDependenciesBlock');
  61. } catch (_) {}
  62. try {
  63. BlockSchemas3[1].DependencyBlock = require('webpack/lib/dependencies/ImportDependenciesBlock');
  64. BlockSchemas4[1].DependencyBlock = require('webpack/lib/dependencies/ImportDependenciesBlock');
  65. } catch (_) {}
  66. try {
  67. BlockSchemas3[2].DependencyBlock = require('webpack/lib/dependencies/RequireEnsureDependenciesBlock');
  68. BlockSchemas4[2].DependencyBlock = require('webpack/lib/dependencies/RequireEnsureDependenciesBlock');
  69. } catch (_) {}
  70. try {
  71. BlockSchemas3[3].DependencyBlock = require('webpack/lib/AsyncDependenciesBlock');
  72. BlockSchemas4[3].DependencyBlock = require('webpack/lib/AsyncDependenciesBlock');
  73. } catch (_) {}
  74. const freezeArgument = {
  75. chunkName(arg, { chunkName }, extra, methods) {
  76. return chunkName;
  77. },
  78. name(arg, { name }, extra, methods) {
  79. return name;
  80. },
  81. groupOptions(arg, { groupOptions }) {
  82. return groupOptions;
  83. },
  84. module(arg, block, extra, methods) {},
  85. originModule(arg, block, extra, methods) {},
  86. };
  87. const thawArgument = {
  88. module(arg, frozen, extra, methods) {
  89. return extra.module;
  90. },
  91. originModule(arg, block, extra, methods) {
  92. return extra.module;
  93. },
  94. };
  95. function freezeDependencyBlock(dependencyBlock, extra, methods) {
  96. const schemas = extra.schemas;
  97. for (let i = 0; i < schemas.length; i++) {
  98. if (dependencyBlock.constructor === schemas[i].DependencyBlock) {
  99. const frozen = {
  100. type: schemas[i][0],
  101. };
  102. for (let j = 1; j < schemas[i].length; j++) {
  103. let arg = dependencyBlock[schemas[i][j]];
  104. if (freezeArgument[schemas[i][j]]) {
  105. arg = freezeArgument[schemas[i][j]](
  106. arg,
  107. dependencyBlock,
  108. extra,
  109. methods,
  110. );
  111. }
  112. frozen[schemas[i][j]] = arg;
  113. }
  114. return frozen;
  115. }
  116. }
  117. }
  118. function thawDependencyBlock(frozen, extra, methods) {
  119. const schemas = extra.schemas;
  120. for (let i = 0; i < schemas.length; i++) {
  121. if (frozen.type === schemas[i][0]) {
  122. const DependencyBlock = schemas[i].DependencyBlock;
  123. const args = [];
  124. for (let j = 1; j < schemas[i].length; j++) {
  125. let arg = frozen[schemas[i][j]];
  126. if (thawArgument[schemas[i][j]]) {
  127. arg = thawArgument[schemas[i][j]](arg, frozen, extra, methods);
  128. }
  129. args.push(arg);
  130. }
  131. try {
  132. return new DependencyBlock(...args);
  133. } catch (_) {
  134. return new (Function.prototype.bind.apply(
  135. DependencyBlock,
  136. [null].concat(args),
  137. ))();
  138. }
  139. }
  140. }
  141. }
  142. function assertFrozen({ length }, original, typeName, freeze) {
  143. if (length !== original.length) {
  144. const didNotFreeze = original.filter(item => !freeze(item));
  145. if (didNotFreeze.length > 0) {
  146. throw new Error(
  147. `Unfrozen ${typeName} (${didNotFreeze.length} / ${
  148. original.length
  149. }): ${didNotFreeze
  150. .map(({ constructor }) => constructor.name)
  151. .filter((name, i, names) => !names.slice(0, i).includes(name))
  152. .join(', ')}`,
  153. );
  154. }
  155. }
  156. }
  157. class TransformDependencyBlockPlugin {
  158. constructor(options) {
  159. this.options = options;
  160. }
  161. apply(compiler) {
  162. let schemas = BlockSchemas4;
  163. if (this.options.schema < 4) {
  164. schemas = BlockSchemas3;
  165. }
  166. let methods;
  167. pluginCompat.tap(
  168. compiler,
  169. '_hardSourceMethods',
  170. 'TransformDependencyBlockPlugin',
  171. _methods => {
  172. methods = _methods;
  173. },
  174. );
  175. let freeze;
  176. let mapFreeze;
  177. let mapThaw;
  178. pluginCompat.tap(
  179. compiler,
  180. '_hardSourceMethods',
  181. 'TransformDependencyBlockPlugin',
  182. methods => {
  183. // store = methods.store;
  184. // fetch = methods.fetch;
  185. freeze = methods.freeze;
  186. // thaw = methods.thaw;
  187. mapFreeze = methods.mapFreeze;
  188. mapThaw = methods.mapThaw;
  189. },
  190. );
  191. pluginCompat.tap(
  192. compiler,
  193. '_hardSourceFreezeDependencyVariable',
  194. 'TransformDependencyBlockPlugin',
  195. (frozen, { name, expression, dependencies }, extra) => ({
  196. type: 'DependenciesBlockVariable',
  197. name: name,
  198. expression: expression,
  199. dependencies: mapFreeze('Dependency', null, dependencies, extra),
  200. }),
  201. );
  202. pluginCompat.tap(
  203. compiler,
  204. '_hardSourceFreezeDependencyBlock',
  205. 'TransformDependencyBlockPlugin',
  206. (frozen, block, extra) => {
  207. extra.schemas = schemas;
  208. const _frozen = freezeDependencyBlock(block, extra, methods);
  209. if (_frozen) {
  210. if (
  211. (block.dependencies && block.dependencies.length > 0) ||
  212. (block.variables && block.variables.length > 0) ||
  213. (block.blocks && block.blocks.length > 0)
  214. ) {
  215. _frozen.dependencies = mapFreeze(
  216. 'Dependency',
  217. null,
  218. block.dependencies,
  219. extra,
  220. );
  221. assertFrozen(
  222. _frozen.dependencies,
  223. block.dependencies,
  224. 'dependencies',
  225. item => freeze('Dependency', null, item, extra),
  226. );
  227. _frozen.variables = mapFreeze(
  228. 'DependencyVariable',
  229. null,
  230. block.variables,
  231. extra,
  232. );
  233. assertFrozen(
  234. _frozen.variables,
  235. block.variables,
  236. 'dependency variables',
  237. item => freeze('DependencyVariable', null, item, extra),
  238. );
  239. _frozen.blocks = mapFreeze(
  240. 'DependencyBlock',
  241. null,
  242. block.blocks,
  243. extra,
  244. );
  245. assertFrozen(_frozen.blocks, block.blocks, 'blocks', item =>
  246. freeze('DependencyBlock', null, item, extra),
  247. );
  248. }
  249. if (block.parent) {
  250. _frozen.parent = true;
  251. }
  252. return _frozen;
  253. }
  254. const _frozenBlock = {
  255. type: 'DependenciesBlock',
  256. dependencies: mapFreeze(
  257. 'Dependency',
  258. null,
  259. block.dependencies,
  260. extra,
  261. ),
  262. variables: mapFreeze(
  263. 'DependencyVariable',
  264. null,
  265. block.variables,
  266. extra,
  267. ),
  268. blocks: mapFreeze('DependencyBlock', null, block.blocks, extra),
  269. };
  270. assertFrozen(
  271. _frozenBlock.dependencies,
  272. block.dependencies,
  273. 'dependencies',
  274. item => freeze('Dependency', null, item, extra),
  275. );
  276. assertFrozen(
  277. _frozenBlock.variables,
  278. block.variables,
  279. 'dependency variables',
  280. item => freeze('DependencyVariable', null, item, extra),
  281. );
  282. assertFrozen(_frozenBlock.blocks, block.blocks, 'blocks', item =>
  283. freeze('DependencyBlock', null, item, extra),
  284. );
  285. return _frozenBlock;
  286. },
  287. );
  288. pluginCompat.tap(
  289. compiler,
  290. '_hardSourceThawDependencyVariable',
  291. 'TransformDependencyBlockPlugin',
  292. (variable, { name, expression, dependencies }, extra) =>
  293. new DependenciesBlockVariable(
  294. name,
  295. expression,
  296. mapThaw('Dependency', null, dependencies, extra),
  297. ),
  298. );
  299. pluginCompat.tap(
  300. compiler,
  301. '_hardSourceThawDependencyBlock',
  302. 'TransformDependencyBlockPlugin',
  303. (block, frozen, extra) => {
  304. extra.schemas = schemas;
  305. const _thawed = thawDependencyBlock(frozen, extra, methods);
  306. if (_thawed) {
  307. if (_thawed.dependencies) {
  308. var blockExtra = {
  309. state: extra.state,
  310. module: extra.module,
  311. parent: _thawed,
  312. compilation: extra.compilation,
  313. };
  314. _thawed.dependencies = mapThaw(
  315. 'Dependency',
  316. null,
  317. frozen.dependencies,
  318. blockExtra,
  319. );
  320. _thawed.variables = mapThaw(
  321. 'DependencyVariable',
  322. null,
  323. frozen.variables,
  324. blockExtra,
  325. );
  326. mapThaw('DependencyBlock', null, frozen.blocks, blockExtra);
  327. }
  328. if (frozen.parent) {
  329. extra.parent.addBlock(_thawed);
  330. }
  331. return _thawed;
  332. }
  333. if (block) {
  334. var blockExtra = {
  335. state: extra.state,
  336. module: extra.module,
  337. parent: block,
  338. compilation: extra.compilation,
  339. };
  340. block.dependencies = mapThaw(
  341. 'Dependency',
  342. null,
  343. frozen.dependencies,
  344. blockExtra,
  345. );
  346. block.variables = mapThaw(
  347. 'DependencyVariable',
  348. null,
  349. frozen.variables,
  350. blockExtra,
  351. );
  352. block.blocks = mapThaw(
  353. 'DependencyBlock',
  354. null,
  355. frozen.blocks,
  356. blockExtra,
  357. );
  358. }
  359. return block;
  360. },
  361. );
  362. }
  363. }
  364. module.exports = TransformDependencyBlockPlugin;