@@ -15,8 +15,11 @@ const BundleBase = require('./BundleBase');
1515const ModuleTransport = require ( '../lib/ModuleTransport' ) ;
1616
1717const _ = require ( 'lodash' ) ;
18- const base64VLQ = require ( './base64-vlq' ) ;
1918const crypto = require ( 'crypto' ) ;
19+ const debug = require ( 'debug' ) ( 'RNP:Bundle' ) ;
20+ const invariant = require ( 'fbjs/lib/invariant' ) ;
21+
22+ const { fromRawMappings} = require ( './source-map' ) ;
2023
2124import type { SourceMap , CombinedSourceMap , MixedSourceMap } from '../lib/SourceMap' ;
2225import type { GetSourceOptions , FinalizeOptions } from './BundleBase' ;
@@ -27,6 +30,8 @@ export type Unbundle = {
2730 groups : Map < number , Set < number> > ,
2831} ;
2932
33+ type SourceMapFormat = 'undetermined' | 'indexed' | 'flattened' ;
34+
3035const SOURCEMAPPING_URL = '\n\/\/# sourceMappingURL=' ;
3136
3237class Bundle extends BundleBase {
@@ -37,8 +42,8 @@ class Bundle extends BundleBase {
3742 _numRequireCalls : number ;
3843 _ramBundle : Unbundle | null ;
3944 _ramGroups : Array < string > | void ;
40- _shouldCombineSourceMaps : boolean ;
41- _sourceMap : boolean ;
45+ _sourceMap : string | null ;
46+ _sourceMapFormat : SourceMapFormat ;
4247 _sourceMapUrl : string | void ;
4348
4449 constructor ( { sourceMapUrl, dev, minify, ramGroups} : {
@@ -48,9 +53,9 @@ class Bundle extends BundleBase {
4853 ramGroups ?: Array < string > ,
4954 } = { } ) {
5055 super ( ) ;
51- this . _sourceMap = false ;
56+ this . _sourceMap = null ;
57+ this . _sourceMapFormat = 'undetermined' ;
5258 this . _sourceMapUrl = sourceMapUrl ;
53- this . _shouldCombineSourceMaps = false ;
5459 this . _numRequireCalls = 0 ;
5560 this . _dev = dev ;
5661 this . _minify = minify ;
@@ -86,8 +91,22 @@ class Bundle extends BundleBase {
8691 } ) . then ( ( { code, map} ) => {
8792 // If we get a map from the transformer we'll switch to a mode
8893 // were we're combining the source maps as opposed to
89- if ( ! this . _shouldCombineSourceMaps && map != null ) {
90- this . _shouldCombineSourceMaps = true ;
94+ if ( map ) {
95+ const usesRawMappings = isRawMappings ( map ) ;
96+
97+ if ( this . _sourceMapFormat === 'undetermined' ) {
98+ this . _sourceMapFormat = usesRawMappings ? 'flattened' : 'indexed' ;
99+ } else if ( usesRawMappings && this . _sourceMapFormat === 'indexed' ) {
100+ throw new Error (
101+ `Got at least one module with a full source map, but ${
102+ moduleTransport . sourcePath } has raw mappings`
103+ ) ;
104+ } else if ( ! usesRawMappings && this . _sourceMapFormat === 'flattened' ) {
105+ throw new Error (
106+ `Got at least one module with raw mappings, but ${
107+ moduleTransport . sourcePath } has a full source map`
108+ ) ;
109+ }
91110 }
92111
93112 this . replaceModuleAt (
@@ -103,7 +122,7 @@ class Bundle extends BundleBase {
103122 options . runBeforeMainModule . forEach ( this . _addRequireCall , this ) ;
104123 /* $FlowFixMe: this is unsound, as nothing enforces the module ID to have
105124 * been set beforehand. */
106- this . _addRequireCall ( super . getMainModuleId ( ) ) ;
125+ this . _addRequireCall ( this . getMainModuleId ( ) ) ;
107126 }
108127
109128 super . finalize ( options ) ;
@@ -126,16 +145,16 @@ class Bundle extends BundleBase {
126145
127146 _getInlineSourceMap(dev) {
128147 if (this._inlineSourceMap == null) {
129- const sourceMap = this.getSourceMap ({excludeSource: true, dev});
148+ const sourceMap = this.getSourceMapString ({excludeSource: true, dev});
130149 /*eslint-env node*/
131- const encoded = new Buffer(JSON.stringify( sourceMap) ).toString('base64');
150+ const encoded = new Buffer(sourceMap).toString('base64');
132151 this._inlineSourceMap = 'data:application/json;base64,' + encoded;
133152 }
134153 return this._inlineSourceMap;
135154 }
136155
137156 getSource(options: GetSourceOptions) {
138- super .assertFinalized();
157+ this .assertFinalized();
139158
140159 options = options || {};
141160
@@ -175,6 +194,12 @@ class Bundle extends BundleBase {
175194 return this._ramBundle;
176195 }
177196
197+ invalidateSource() {
198+ debug('invalidating bundle');
199+ super.invalidateSource();
200+ this._sourceMap = null;
201+ }
202+
178203 /**
179204 * Combine each of the sourcemaps multiple modules have into a single big
180205 * one. This works well thanks to a neat trick defined on the sourcemap spec
@@ -190,23 +215,22 @@ class Bundle extends BundleBase {
190215
191216 let line = 0;
192217 this.getModules().forEach(module => {
193- let map = module.map;
218+ let map = module.map == null || module.virtual
219+ ? generateSourceMapForVirtualModule(module)
220+ : module.map;
194221
195- if (module.virtual) {
196- map = generateSourceMapForVirtualModule(module);
197- }
222+ invariant(
223+ !Array.isArray(map),
224+ ` Unexpected raw mappings for ${module . sourcePath } `,
225+ );
198226
199- if (options.excludeSource) {
200- /* $FlowFixMe: assume the map is not empty if we got here. */
201- if (map.sourcesContent && map.sourcesContent.length) {
202- map = Object.assign({}, map, {sourcesContent: []});
203- }
227+ if (options.excludeSource && 'sourcesContent' in map) {
228+ map = {...map, sourcesContent: []};
204229 }
205230
206231 result.sections.push({
207232 offset: { line: line, column: 0 },
208- /* $FlowFixMe: assume the map is not empty if we got here. */
209- map: map,
233+ map: (map: MixedSourceMap),
210234 });
211235 line += module.code.split('\n').length;
212236 });
@@ -215,23 +239,30 @@ class Bundle extends BundleBase {
215239 }
216240
217241 getSourceMap(options: {excludeSource?: boolean}): MixedSourceMap {
218- super.assertFinalized();
242+ this.assertFinalized();
243+
244+ return this._sourceMapFormat === 'indexed'
245+ ? this._getCombinedSourceMaps(options)
246+ : fromRawMappings(this.getModules()).toMap();
247+ }
219248
220- if (this._shouldCombineSourceMaps) {
221- return this._getCombinedSourceMaps(options);
249+ getSourceMapString(options: {excludeSource?: boolean}): string {
250+ if (this._sourceMapFormat === 'indexed') {
251+ return JSON.stringify(this.getSourceMap(options));
222252 }
223253
224- const mappings = this._getMappings();
225- const modules = this.getModules();
226- const map = {
227- file: this._getSourceMapFile(),
228- sources: modules.map(module => module.sourcePath),
229- version: 3,
230- names: [],
231- mappings: mappings,
232- sourcesContent: options.excludeSource
233- ? [] : modules.map(module => module.sourceCode),
234- };
254+ // The following code is an optimization specific to the development server:
255+ // 1. generator.toSource() is faster than JSON.stringify(generator.toMap()).
256+ // 2. caching the source map unless there are changes saves time in
257+ // development settings.
258+ let map = this._sourceMap;
259+ if (map == null) {
260+ debug('Start building flat source map');
261+ map = this._sourceMap = fromRawMappings(this.getModules()).toString();
262+ debug('End building flat source map');
263+ } else {
264+ debug('Returning cached source map');
265+ }
235266 return map;
236267 }
237268
@@ -248,53 +279,6 @@ class Bundle extends BundleBase {
248279 : 'bundle.js';
249280 }
250281
251- _getMappings() {
252- const modules = super.getModules();
253-
254- // The first line mapping in our package is basically the base64vlq code for
255- // zeros (A).
256- const firstLine = 'AAAA';
257-
258- // Most other lines in our mappings are all zeros (for module, column etc)
259- // except for the lineno mappinp: curLineno - prevLineno = 1; Which is C.
260- const line = 'AACA';
261-
262- const moduleLines = Object.create(null);
263- let mappings = '';
264- for (let i = 0; i < modules.length; i++) {
265- const module = modules[i];
266- const code = module.code;
267- let lastCharNewLine = false;
268- moduleLines[module.sourcePath] = 0;
269- for (let t = 0; t < code.length; t++) {
270- if (t === 0 && i === 0) {
271- mappings += firstLine;
272- } else if (t === 0) {
273- mappings += 'AC';
274-
275- // This is the only place were we actually don't know the mapping ahead
276- // of time. When it's a new module (and not the first) the lineno
277- // mapping is 0 (current) - number of lines in prev module.
278- mappings += base64VLQ.encode(
279- 0 - moduleLines[modules[i - 1].sourcePath]
280- );
281- mappings += 'A';
282- } else if (lastCharNewLine) {
283- moduleLines[module.sourcePath]++;
284- mappings += line;
285- }
286- lastCharNewLine = code[t] === '\n';
287- if (lastCharNewLine) {
288- mappings += ';';
289- }
290- }
291- if (i !== modules.length - 1) {
292- mappings += ';';
293- }
294- }
295- return mappings;
296- }
297-
298282 getJSModulePaths() {
299283 return this.getModules()
300284 // Filter out non-js files. Like images etc.
@@ -305,7 +289,7 @@ class Bundle extends BundleBase {
305289 getDebugInfo() {
306290 return [
307291 /* $FlowFixMe: this is unsound as the module ID could be unset. */
308- '<div><h3>Main Module:</h3> ' + super .getMainModuleId() + '</div>',
292+ '<div><h3>Main Module:</h3> ' + this .getMainModuleId() + '</div>',
309293 '<style>',
310294 'pre.collapsed {',
311295 ' height: 10px;',
@@ -328,30 +312,6 @@ class Bundle extends BundleBase {
328312 setRamGroups(ramGroups: Array<string>) {
329313 this._ramGroups = ramGroups;
330314 }
331-
332- toJSON() {
333- this.assertFinalized('Cannot serialize bundle unless finalized');
334-
335- return {
336- ...super.toJSON(),
337- sourceMapUrl: this._sourceMapUrl,
338- numRequireCalls: this._numRequireCalls,
339- shouldCombineSourceMaps: this._shouldCombineSourceMaps,
340- };
341- }
342-
343- static fromJSON(json) {
344- const bundle = new Bundle({sourceMapUrl: json.sourceMapUrl});
345-
346- bundle._sourceMapUrl = json.sourceMapUrl;
347- bundle._numRequireCalls = json.numRequireCalls;
348- bundle._shouldCombineSourceMaps = json.shouldCombineSourceMaps;
349-
350- BundleBase.fromJSON(bundle, json);
351-
352- /* $FlowFixMe: this modifies BundleBase#fromJSON() signature. */
353- return bundle;
354- }
355315}
356316
357317function generateSourceMapForVirtualModule(module): SourceMap {
@@ -472,4 +432,6 @@ function createGroups(ramGroups: Array<string>, lazyModules) {
472432 return result ;
473433}
474434
435+ const isRawMappings = Array . isArray ;
436+
475437module . exports = Bundle ;
0 commit comments