UNPKG

7.14 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
6
7const traverse = require('@babel/traverse').default;
8
9const codeFrame = require('@babel/code-frame').codeFrameColumns;
10
11const collectDependencies = require('../visitors/dependencies');
12
13const walk = require('babylon-walk');
14
15const Asset = require('../Asset');
16
17const babelParser = require('@babel/parser');
18
19const insertGlobals = require('../visitors/globals');
20
21const fsVisitor = require('../visitors/fs');
22
23const envVisitor = require('../visitors/env');
24
25const processVisitor = require('../visitors/process');
26
27const babel = require('../transforms/babel/transform');
28
29const babel7 = require('../transforms/babel/babel7');
30
31const generate = require('@babel/generator').default;
32
33const terser = require('../transforms/terser');
34
35const SourceMap = require('../SourceMap');
36
37const hoist = require('../scope-hoisting/hoist');
38
39const loadSourceMap = require('../utils/loadSourceMap');
40
41const isAccessedVarChanged = require('../utils/isAccessedVarChanged');
42
43const IMPORT_RE = /\b(?:import\b|export\b|require\s*\()/;
44const ENV_RE = /\b(?:process\.env)\b/;
45const BROWSER_RE = /\b(?:process\.browser)\b/;
46const GLOBAL_RE = /\b(?:process|__dirname|__filename|global|Buffer|define)\b/;
47const FS_RE = /\breadFileSync\b/;
48const SW_RE = /\bnavigator\s*\.\s*serviceWorker\s*\.\s*register\s*\(/;
49const WORKER_RE = /\bnew\s*(?:Shared)?Worker\s*\(/;
50
51class JSAsset extends Asset {
52 constructor(name, options) {
53 super(name, options);
54 this.type = 'js';
55 this.globals = new Map();
56 this.isAstDirty = false;
57 this.isES6Module = false;
58 this.outputCode = null;
59 this.cacheData.env = {};
60 this.rendition = options.rendition;
61 this.sourceMap = this.rendition ? this.rendition.map : null;
62 }
63
64 shouldInvalidate(cacheData) {
65 return isAccessedVarChanged(cacheData);
66 }
67
68 mightHaveDependencies() {
69 return this.isAstDirty || !/\.js$/.test(this.name) || IMPORT_RE.test(this.contents) || GLOBAL_RE.test(this.contents) || SW_RE.test(this.contents) || WORKER_RE.test(this.contents);
70 }
71
72 parse(code) {
73 var _this = this;
74
75 return (0, _asyncToGenerator2.default)(function* () {
76 return babelParser.parse(code, {
77 filename: _this.name,
78 allowReturnOutsideFunction: true,
79 strictMode: false,
80 sourceType: 'module',
81 plugins: ['exportDefaultFrom', 'exportNamespaceFrom', 'dynamicImport']
82 });
83 })();
84 }
85
86 traverse(visitor) {
87 return traverse(this.ast, visitor, null, this);
88 }
89
90 traverseFast(visitor) {
91 return walk.simple(this.ast, visitor, this);
92 }
93
94 collectDependencies() {
95 walk.ancestor(this.ast, collectDependencies, this);
96 }
97
98 pretransform() {
99 var _this2 = this;
100
101 return (0, _asyncToGenerator2.default)(function* () {
102 if (_this2.options.sourceMaps && !_this2.sourceMap) {
103 _this2.sourceMap = yield loadSourceMap(_this2);
104 }
105
106 yield babel(_this2); // Inline environment variables
107
108 if (_this2.options.target === 'browser' && ENV_RE.test(_this2.contents)) {
109 yield _this2.parseIfNeeded();
110
111 _this2.traverseFast(envVisitor);
112 } // Inline process.browser
113
114
115 if (_this2.options.target === 'browser' && BROWSER_RE.test(_this2.contents)) {
116 yield _this2.parseIfNeeded();
117
118 _this2.traverse(processVisitor);
119
120 _this2.isAstDirty = true;
121 }
122 })();
123 }
124
125 transform() {
126 var _this3 = this;
127
128 return (0, _asyncToGenerator2.default)(function* () {
129 if (_this3.options.target === 'browser') {
130 if (_this3.dependencies.has('fs') && FS_RE.test(_this3.contents)) {
131 // Check if we should ignore fs calls
132 // See https://github.com/defunctzombie/node-browser-resolve#skip
133 let pkg = yield _this3.getPackage();
134 let ignore = pkg && pkg.browser && pkg.browser.fs === false;
135
136 if (!ignore) {
137 yield _this3.parseIfNeeded();
138
139 _this3.traverse(fsVisitor);
140 }
141 }
142
143 if (GLOBAL_RE.test(_this3.contents)) {
144 yield _this3.parseIfNeeded();
145 walk.ancestor(_this3.ast, insertGlobals, _this3);
146 }
147 }
148
149 if (_this3.options.scopeHoist) {
150 yield _this3.parseIfNeeded();
151 yield _this3.getPackage();
152
153 _this3.traverse(hoist);
154
155 _this3.isAstDirty = true;
156 } else {
157 if (_this3.isES6Module) {
158 yield babel7(_this3, {
159 internal: true,
160 config: {
161 plugins: [require('@babel/plugin-transform-modules-commonjs')]
162 }
163 });
164 }
165 }
166
167 if (_this3.options.minify) {
168 yield terser(_this3);
169 }
170 })();
171 }
172
173 generate() {
174 var _this4 = this;
175
176 return (0, _asyncToGenerator2.default)(function* () {
177 let code;
178
179 if (_this4.isAstDirty) {
180 let opts = {
181 sourceMaps: _this4.options.sourceMaps,
182 sourceFileName: _this4.relativeName
183 };
184 let generated = generate(_this4.ast, opts, _this4.contents);
185
186 if (_this4.options.sourceMaps && generated.rawMappings) {
187 let rawMap = new SourceMap(generated.rawMappings, {
188 [_this4.relativeName]: _this4.contents
189 }); // Check if we already have a source map (e.g. from TypeScript or CoffeeScript)
190 // In that case, we need to map the original source map to the babel generated one.
191
192 if (_this4.sourceMap) {
193 _this4.sourceMap = yield new SourceMap().extendSourceMap(_this4.sourceMap, rawMap);
194 } else {
195 _this4.sourceMap = rawMap;
196 }
197 }
198
199 code = generated.code;
200 } else {
201 code = _this4.outputCode != null ? _this4.outputCode : _this4.contents;
202 }
203
204 if (_this4.options.sourceMaps && !_this4.sourceMap) {
205 _this4.sourceMap = new SourceMap().generateEmptyMap(_this4.relativeName, _this4.contents);
206 }
207
208 if (_this4.globals.size > 0) {
209 code = Array.from(_this4.globals.values()).join('\n') + '\n' + code;
210
211 if (_this4.options.sourceMaps) {
212 if (!(_this4.sourceMap instanceof SourceMap)) {
213 _this4.sourceMap = yield new SourceMap().addMap(_this4.sourceMap);
214 }
215
216 _this4.sourceMap.offset(_this4.globals.size);
217 }
218 }
219
220 return [{
221 type: 'js',
222 value: code,
223 map: _this4.sourceMap
224 }];
225 })();
226 }
227
228 generateErrorMessage(err) {
229 const loc = err.loc;
230
231 if (loc) {
232 // Babel 7 adds its own code frame on the error message itself
233 // We need to remove it and pass it separately.
234 if (err.message.startsWith(this.name)) {
235 err.message = err.message.slice(this.name.length + 1, err.message.indexOf('\n')).trim();
236 }
237
238 err.codeFrame = codeFrame(this.contents, {
239 start: loc
240 });
241 err.highlightedCodeFrame = codeFrame(this.contents, {
242 start: loc
243 }, {
244 highlightCode: true
245 });
246 }
247
248 return err;
249 }
250
251}
252
253module.exports = JSAsset;
\No newline at end of file