URLPlugin.js (3189B)
1 /* 2 MIT License http://www.opensource.org/licenses/mit-license.php 3 Author Ivan Kopeykin @vankop 4 */ 5 6 "use strict"; 7 8 const { approve } = require("../javascript/JavascriptParserHelpers"); 9 const InnerGraph = require("../optimize/InnerGraph"); 10 const URLDependency = require("./URLDependency"); 11 12 /** @typedef {import("estree").NewExpression} NewExpressionNode */ 13 /** @typedef {import("../Compiler")} Compiler */ 14 /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */ 15 16 class URLPlugin { 17 /** 18 * @param {Compiler} compiler compiler 19 */ 20 apply(compiler) { 21 compiler.hooks.compilation.tap( 22 "URLPlugin", 23 (compilation, { normalModuleFactory }) => { 24 compilation.dependencyFactories.set(URLDependency, normalModuleFactory); 25 compilation.dependencyTemplates.set( 26 URLDependency, 27 new URLDependency.Template() 28 ); 29 30 /** 31 * @param {JavascriptParser} parser parser 32 * @param {object} parserOptions options 33 */ 34 const parserCallback = (parser, parserOptions) => { 35 if (parserOptions.url === false) return; 36 const relative = parserOptions.url === "relative"; 37 38 /** 39 * @param {NewExpressionNode} expr expression 40 * @returns {undefined | string} request 41 */ 42 const getUrlRequest = expr => { 43 if (expr.arguments.length !== 2) return; 44 45 const [arg1, arg2] = expr.arguments; 46 47 if ( 48 arg2.type !== "MemberExpression" || 49 arg1.type === "SpreadElement" 50 ) 51 return; 52 53 const chain = parser.extractMemberExpressionChain(arg2); 54 55 if ( 56 chain.members.length !== 1 || 57 chain.object.type !== "MetaProperty" || 58 chain.object.meta.name !== "import" || 59 chain.object.property.name !== "meta" || 60 chain.members[0] !== "url" 61 ) 62 return; 63 64 const request = parser.evaluateExpression(arg1).asString(); 65 66 return request; 67 }; 68 69 parser.hooks.canRename.for("URL").tap("URLPlugin", approve); 70 parser.hooks.new.for("URL").tap("URLPlugin", _expr => { 71 const expr = /** @type {NewExpressionNode} */ (_expr); 72 73 const request = getUrlRequest(expr); 74 75 if (!request) return; 76 77 const [arg1, arg2] = expr.arguments; 78 const dep = new URLDependency( 79 request, 80 [arg1.range[0], arg2.range[1]], 81 expr.range, 82 relative 83 ); 84 dep.loc = expr.loc; 85 parser.state.current.addDependency(dep); 86 InnerGraph.onUsage(parser.state, e => (dep.usedByExports = e)); 87 return true; 88 }); 89 parser.hooks.isPure.for("NewExpression").tap("URLPlugin", _expr => { 90 const expr = /** @type {NewExpressionNode} */ (_expr); 91 const { callee } = expr; 92 if (callee.type !== "Identifier") return; 93 const calleeInfo = parser.getFreeInfoFromVariable(callee.name); 94 if (!calleeInfo || calleeInfo.name !== "URL") return; 95 96 const request = getUrlRequest(expr); 97 98 if (request) return true; 99 }); 100 }; 101 102 normalModuleFactory.hooks.parser 103 .for("javascript/auto") 104 .tap("URLPlugin", parserCallback); 105 106 normalModuleFactory.hooks.parser 107 .for("javascript/esm") 108 .tap("URLPlugin", parserCallback); 109 } 110 ); 111 } 112 } 113 114 module.exports = URLPlugin;