mirror of https://github.com/status-im/metro.git
metro-bundler: moar @format
Reviewed By: mjesun Differential Revision: D5484885 fbshipit-source-id: f9ae126931f0c9f611ee5b5b96243656e86f4ba4
This commit is contained in:
parent
9f1cce4e89
commit
ce0da03a05
|
@ -5,6 +5,8 @@
|
||||||
* This source code is licensed under the BSD-style license found in the
|
* This source code is licensed under the BSD-style license found in the
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
@ -26,7 +28,7 @@ describe('AssetServer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
root: {
|
||||||
imgs: {
|
imgs: {
|
||||||
'b.png': 'b image',
|
'b.png': 'b image',
|
||||||
'b@2x.png': 'b2 image',
|
'b@2x.png': 'b2 image',
|
||||||
|
@ -37,11 +39,7 @@ describe('AssetServer', () => {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
server.get('imgs/b.png'),
|
server.get('imgs/b.png'),
|
||||||
server.get('imgs/b@1x.png'),
|
server.get('imgs/b@1x.png'),
|
||||||
]).then(resp =>
|
]).then(resp => resp.forEach(data => expect(data).toBe('b image')));
|
||||||
resp.forEach(data =>
|
|
||||||
expect(data).toBe('b image')
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work for the simple case with platform ext', () => {
|
it('should work for the simple case with platform ext', () => {
|
||||||
|
@ -51,7 +49,7 @@ describe('AssetServer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
root: {
|
||||||
imgs: {
|
imgs: {
|
||||||
'b.ios.png': 'b ios image',
|
'b.ios.png': 'b ios image',
|
||||||
'b.android.png': 'b android image',
|
'b.android.png': 'b android image',
|
||||||
|
@ -62,25 +60,24 @@ describe('AssetServer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
server.get('imgs/b.png', 'ios').then(
|
server
|
||||||
data => expect(data).toBe('b ios image')
|
.get('imgs/b.png', 'ios')
|
||||||
),
|
.then(data => expect(data).toBe('b ios image')),
|
||||||
server.get('imgs/b.png', 'android').then(
|
server
|
||||||
data => expect(data).toBe('b android image')
|
.get('imgs/b.png', 'android')
|
||||||
),
|
.then(data => expect(data).toBe('b android image')),
|
||||||
server.get('imgs/c.png', 'android').then(
|
server
|
||||||
data => expect(data).toBe('c android image')
|
.get('imgs/c.png', 'android')
|
||||||
),
|
.then(data => expect(data).toBe('c android image')),
|
||||||
server.get('imgs/c.png', 'ios').then(
|
server
|
||||||
data => expect(data).toBe('c general image')
|
.get('imgs/c.png', 'ios')
|
||||||
),
|
.then(data => expect(data).toBe('c general image')),
|
||||||
server.get('imgs/c.png').then(
|
server
|
||||||
data => expect(data).toBe('c general image')
|
.get('imgs/c.png')
|
||||||
),
|
.then(data => expect(data).toBe('c general image')),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should work for the simple case with jpg', () => {
|
it('should work for the simple case with jpg', () => {
|
||||||
const server = new AssetServer({
|
const server = new AssetServer({
|
||||||
projectRoots: ['/root'],
|
projectRoots: ['/root'],
|
||||||
|
@ -88,7 +85,7 @@ describe('AssetServer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
root: {
|
||||||
imgs: {
|
imgs: {
|
||||||
'b.png': 'png image',
|
'b.png': 'png image',
|
||||||
'b.jpg': 'jpeg image',
|
'b.jpg': 'jpeg image',
|
||||||
|
@ -99,12 +96,7 @@ describe('AssetServer', () => {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
server.get('imgs/b.jpg'),
|
server.get('imgs/b.jpg'),
|
||||||
server.get('imgs/b.png'),
|
server.get('imgs/b.png'),
|
||||||
]).then(data =>
|
]).then(data => expect(data).toEqual(['jpeg image', 'png image']));
|
||||||
expect(data).toEqual([
|
|
||||||
'jpeg image',
|
|
||||||
'png image',
|
|
||||||
])
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should pick the bigger one', () => {
|
it('should pick the bigger one', () => {
|
||||||
|
@ -114,7 +106,7 @@ describe('AssetServer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
root: {
|
||||||
imgs: {
|
imgs: {
|
||||||
'b@1x.png': 'b1 image',
|
'b@1x.png': 'b1 image',
|
||||||
'b@2x.png': 'b2 image',
|
'b@2x.png': 'b2 image',
|
||||||
|
@ -124,9 +116,9 @@ describe('AssetServer', () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return server.get('imgs/b@3x.png').then(data =>
|
return server
|
||||||
expect(data).toBe('b4 image')
|
.get('imgs/b@3x.png')
|
||||||
);
|
.then(data => expect(data).toBe('b4 image'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should pick the bigger one with platform ext', () => {
|
it('should pick the bigger one with platform ext', () => {
|
||||||
|
@ -136,7 +128,7 @@ describe('AssetServer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
root: {
|
||||||
imgs: {
|
imgs: {
|
||||||
'b@1x.png': 'b1 image',
|
'b@1x.png': 'b1 image',
|
||||||
'b@2x.png': 'b2 image',
|
'b@2x.png': 'b2 image',
|
||||||
|
@ -151,12 +143,10 @@ describe('AssetServer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
server.get('imgs/b@3x.png').then(data =>
|
server.get('imgs/b@3x.png').then(data => expect(data).toBe('b4 image')),
|
||||||
expect(data).toBe('b4 image')
|
server
|
||||||
),
|
.get('imgs/b@3x.png', 'ios')
|
||||||
server.get('imgs/b@3x.png', 'ios').then(data =>
|
.then(data => expect(data).toBe('b4 ios image')),
|
||||||
expect(data).toBe('b4 ios image')
|
|
||||||
),
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -167,23 +157,23 @@ describe('AssetServer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
root: {
|
||||||
imgs: {
|
imgs: {
|
||||||
'b.png': 'b image',
|
'b.png': 'b image',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'root2': {
|
root2: {
|
||||||
'newImages': {
|
newImages: {
|
||||||
'imgs': {
|
imgs: {
|
||||||
'b@1x.png': 'b1 image',
|
'b@1x.png': 'b1 image',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return server.get('newImages/imgs/b.png').then(data =>
|
return server
|
||||||
expect(data).toBe('b1 image')
|
.get('newImages/imgs/b.png')
|
||||||
);
|
.then(data => expect(data).toBe('b1 image'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -195,7 +185,7 @@ describe('AssetServer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
root: {
|
||||||
imgs: {
|
imgs: {
|
||||||
'b@1x.png': 'b1 image',
|
'b@1x.png': 'b1 image',
|
||||||
'b@2x.png': 'b2 image',
|
'b@2x.png': 'b2 image',
|
||||||
|
@ -206,17 +196,19 @@ describe('AssetServer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
return server.getAssetData('imgs/b.png').then(data => {
|
return server.getAssetData('imgs/b.png').then(data => {
|
||||||
expect(data).toEqual(objectContaining({
|
expect(data).toEqual(
|
||||||
type: 'png',
|
objectContaining({
|
||||||
name: 'b',
|
type: 'png',
|
||||||
scales: [1, 2, 4, 4.5],
|
name: 'b',
|
||||||
files: [
|
scales: [1, 2, 4, 4.5],
|
||||||
'/root/imgs/b@1x.png',
|
files: [
|
||||||
'/root/imgs/b@2x.png',
|
'/root/imgs/b@1x.png',
|
||||||
'/root/imgs/b@4x.png',
|
'/root/imgs/b@2x.png',
|
||||||
'/root/imgs/b@4.5x.png',
|
'/root/imgs/b@4x.png',
|
||||||
],
|
'/root/imgs/b@4.5x.png',
|
||||||
}));
|
],
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -227,7 +219,7 @@ describe('AssetServer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
root: {
|
||||||
imgs: {
|
imgs: {
|
||||||
'b@1x.jpg': 'b1 image',
|
'b@1x.jpg': 'b1 image',
|
||||||
'b@2x.jpg': 'b2 image',
|
'b@2x.jpg': 'b2 image',
|
||||||
|
@ -238,17 +230,19 @@ describe('AssetServer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
return server.getAssetData('imgs/b.jpg').then(data => {
|
return server.getAssetData('imgs/b.jpg').then(data => {
|
||||||
expect(data).toEqual(objectContaining({
|
expect(data).toEqual(
|
||||||
type: 'jpg',
|
objectContaining({
|
||||||
name: 'b',
|
type: 'jpg',
|
||||||
scales: [1, 2, 4, 4.5],
|
name: 'b',
|
||||||
files: [
|
scales: [1, 2, 4, 4.5],
|
||||||
'/root/imgs/b@1x.jpg',
|
files: [
|
||||||
'/root/imgs/b@2x.jpg',
|
'/root/imgs/b@1x.jpg',
|
||||||
'/root/imgs/b@4x.jpg',
|
'/root/imgs/b@2x.jpg',
|
||||||
'/root/imgs/b@4.5x.jpg',
|
'/root/imgs/b@4x.jpg',
|
||||||
],
|
'/root/imgs/b@4.5x.jpg',
|
||||||
}));
|
],
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -261,7 +255,7 @@ describe('AssetServer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
mockFS = {
|
mockFS = {
|
||||||
'root': {
|
root: {
|
||||||
imgs: {
|
imgs: {
|
||||||
'b@1x.jpg': 'b1 image',
|
'b@1x.jpg': 'b1 image',
|
||||||
'b@2x.jpg': 'b2 image',
|
'b@2x.jpg': 'b2 image',
|
||||||
|
@ -280,18 +274,20 @@ describe('AssetServer', () => {
|
||||||
hash.update(mockFS.root.imgs[name]);
|
hash.update(mockFS.root.imgs[name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.getAssetData('imgs/b.jpg').then(data =>
|
return server
|
||||||
expect(data).toEqual(objectContaining({hash: hash.digest('hex')}))
|
.getAssetData('imgs/b.jpg')
|
||||||
);
|
.then(data =>
|
||||||
|
expect(data).toEqual(objectContaining({hash: hash.digest('hex')})),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('changes the hash when the passed-in file watcher emits an `all` event', () => {
|
it('changes the hash when the passed-in file watcher emits an `all` event', () => {
|
||||||
return server.getAssetData('imgs/b.jpg').then(initialData => {
|
return server.getAssetData('imgs/b.jpg').then(initialData => {
|
||||||
mockFS.root.imgs['b@4x.jpg'] = 'updated data';
|
mockFS.root.imgs['b@4x.jpg'] = 'updated data';
|
||||||
server.onFileChange('all', '/root/imgs/b@4x.jpg');
|
server.onFileChange('all', '/root/imgs/b@4x.jpg');
|
||||||
return server.getAssetData('imgs/b.jpg').then(data =>
|
return server
|
||||||
expect(data.hash).not.toEqual(initialData.hash)
|
.getAssetData('imgs/b.jpg')
|
||||||
);
|
.then(data => expect(data.hash).not.toEqual(initialData.hash));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @flow
|
* @flow
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
@ -25,7 +26,6 @@ const readDir = denodeify(fs.readdir);
|
||||||
const readFile = denodeify(fs.readFile);
|
const readFile = denodeify(fs.readFile);
|
||||||
|
|
||||||
class AssetServer {
|
class AssetServer {
|
||||||
|
|
||||||
_roots: $ReadOnlyArray<string>;
|
_roots: $ReadOnlyArray<string>;
|
||||||
_assetExts: $ReadOnlyArray<string>;
|
_assetExts: $ReadOnlyArray<string>;
|
||||||
_hashes: Map<?string, string>;
|
_hashes: Map<?string, string>;
|
||||||
|
@ -57,7 +57,10 @@ class AssetServer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getAssetData(assetPath: string, platform: ?string = null): Promise<{|
|
getAssetData(
|
||||||
|
assetPath: string,
|
||||||
|
platform: ?string = null,
|
||||||
|
): Promise<{|
|
||||||
files: Array<string>,
|
files: Array<string>,
|
||||||
hash: string,
|
hash: string,
|
||||||
name: string,
|
name: string,
|
||||||
|
@ -109,22 +112,17 @@ class AssetServer {
|
||||||
* 4. Then try to pick platform-specific asset records
|
* 4. Then try to pick platform-specific asset records
|
||||||
* 5. Then pick the closest resolution (rounding up) to the requested one
|
* 5. Then pick the closest resolution (rounding up) to the requested one
|
||||||
*/
|
*/
|
||||||
_getAssetRecord(assetPath: string, platform: ?string = null): Promise<{|
|
_getAssetRecord(
|
||||||
|
assetPath: string,
|
||||||
|
platform: ?string = null,
|
||||||
|
): Promise<{|
|
||||||
files: Array<string>,
|
files: Array<string>,
|
||||||
scales: Array<number>,
|
scales: Array<number>,
|
||||||
|}> {
|
|}> {
|
||||||
const filename = path.basename(assetPath);
|
const filename = path.basename(assetPath);
|
||||||
|
|
||||||
return (
|
return this._findRoot(this._roots, path.dirname(assetPath), assetPath)
|
||||||
this._findRoot(
|
.then(dir => Promise.all([dir, readDir(dir)]))
|
||||||
this._roots,
|
|
||||||
path.dirname(assetPath),
|
|
||||||
assetPath,
|
|
||||||
)
|
|
||||||
.then(dir => Promise.all([
|
|
||||||
dir,
|
|
||||||
readDir(dir),
|
|
||||||
]))
|
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const dir = res[0];
|
const dir = res[0];
|
||||||
const files = res[1];
|
const files = res[1];
|
||||||
|
@ -137,8 +135,9 @@ class AssetServer {
|
||||||
|
|
||||||
let record;
|
let record;
|
||||||
if (platform != null) {
|
if (platform != null) {
|
||||||
record = map.get(getAssetKey(assetData.assetName, platform)) ||
|
record =
|
||||||
map.get(assetData.assetName);
|
map.get(getAssetKey(assetData.assetName, platform)) ||
|
||||||
|
map.get(assetData.assetName);
|
||||||
} else {
|
} else {
|
||||||
record = map.get(assetData.assetName);
|
record = map.get(assetData.assetName);
|
||||||
}
|
}
|
||||||
|
@ -146,33 +145,39 @@ class AssetServer {
|
||||||
if (!record) {
|
if (!record) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
/* $FlowFixMe: platform can be null */
|
/* $FlowFixMe: platform can be null */
|
||||||
`Asset not found: ${assetPath} for platform: ${platform}`
|
`Asset not found: ${assetPath} for platform: ${platform}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return record;
|
return record;
|
||||||
})
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_findRoot(roots: $ReadOnlyArray<string>, dir: string, debugInfoFile: string): Promise<string> {
|
_findRoot(
|
||||||
|
roots: $ReadOnlyArray<string>,
|
||||||
|
dir: string,
|
||||||
|
debugInfoFile: string,
|
||||||
|
): Promise<string> {
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
roots.map(root => {
|
roots.map(root => {
|
||||||
const absRoot = path.resolve(root);
|
const absRoot = path.resolve(root);
|
||||||
// important: we want to resolve root + dir
|
// important: we want to resolve root + dir
|
||||||
// to ensure the requested path doesn't traverse beyond root
|
// to ensure the requested path doesn't traverse beyond root
|
||||||
const absPath = path.resolve(root, dir);
|
const absPath = path.resolve(root, dir);
|
||||||
return stat(absPath).then(fstat => {
|
return stat(absPath).then(
|
||||||
// keep asset requests from traversing files
|
fstat => {
|
||||||
// up from the root (e.g. ../../../etc/hosts)
|
// keep asset requests from traversing files
|
||||||
if (!absPath.startsWith(absRoot)) {
|
// up from the root (e.g. ../../../etc/hosts)
|
||||||
|
if (!absPath.startsWith(absRoot)) {
|
||||||
|
return {path: absPath, isValid: false};
|
||||||
|
}
|
||||||
|
return {path: absPath, isValid: fstat.isDirectory()};
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
return {path: absPath, isValid: false};
|
return {path: absPath, isValid: false};
|
||||||
}
|
},
|
||||||
return {path: absPath, isValid: fstat.isDirectory()};
|
);
|
||||||
}, _ => {
|
}),
|
||||||
return {path: absPath, isValid: false};
|
|
||||||
});
|
|
||||||
})
|
|
||||||
).then(stats => {
|
).then(stats => {
|
||||||
for (let i = 0; i < stats.length; i++) {
|
for (let i = 0; i < stats.length; i++) {
|
||||||
if (stats[i].isValid) {
|
if (stats[i].isValid) {
|
||||||
|
@ -183,15 +188,22 @@ class AssetServer {
|
||||||
const rootsString = roots.map(s => `'${s}'`).join(', ');
|
const rootsString = roots.map(s => `'${s}'`).join(', ');
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`'${debugInfoFile}' could not be found, because '${dir}' is not a ` +
|
`'${debugInfoFile}' could not be found, because '${dir}' is not a ` +
|
||||||
`subdirectory of any of the roots (${rootsString})`,
|
`subdirectory of any of the roots (${rootsString})`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_buildAssetMap(dir: string, files: $ReadOnlyArray<string>, platform: ?string): Map<string, {|
|
_buildAssetMap(
|
||||||
files: Array<string>,
|
dir: string,
|
||||||
scales: Array<number>,
|
files: $ReadOnlyArray<string>,
|
||||||
|}> {
|
platform: ?string,
|
||||||
|
): Map<
|
||||||
|
string,
|
||||||
|
{|
|
||||||
|
files: Array<string>,
|
||||||
|
scales: Array<number>,
|
||||||
|
|},
|
||||||
|
> {
|
||||||
const platforms = new Set(platform != null ? [platform] : []);
|
const platforms = new Set(platform != null ? [platform] : []);
|
||||||
const assets = files.map(this._getAssetDataFromName.bind(this, platforms));
|
const assets = files.map(this._getAssetDataFromName.bind(this, platforms));
|
||||||
const map = new Map();
|
const map = new Map();
|
||||||
|
@ -214,7 +226,7 @@ class AssetServer {
|
||||||
const length = record.scales.length;
|
const length = record.scales.length;
|
||||||
|
|
||||||
for (insertIndex = 0; insertIndex < length; insertIndex++) {
|
for (insertIndex = 0; insertIndex < length; insertIndex++) {
|
||||||
if (asset.resolution < record.scales[insertIndex]) {
|
if (asset.resolution < record.scales[insertIndex]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,7 +256,8 @@ function hashFiles(files, hash, callback) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.createReadStream(files.shift())
|
fs
|
||||||
|
.createReadStream(files.shift())
|
||||||
.on('data', data => hash.update(data))
|
.on('data', data => hash.update(data))
|
||||||
.once('end', () => hashFiles(files, hash, callback))
|
.once('end', () => hashFiles(files, hash, callback))
|
||||||
.once('error', error => callback(error));
|
.once('error', error => callback(error));
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @flow
|
* @flow
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
@ -36,10 +37,9 @@ export type Unbundle = {
|
||||||
|
|
||||||
type SourceMapFormat = 'undetermined' | 'indexed' | 'flattened';
|
type SourceMapFormat = 'undetermined' | 'indexed' | 'flattened';
|
||||||
|
|
||||||
const SOURCEMAPPING_URL = '\n\/\/# sourceMappingURL=';
|
const SOURCEMAPPING_URL = '\n//# sourceMappingURL=';
|
||||||
|
|
||||||
class Bundle extends BundleBase {
|
class Bundle extends BundleBase {
|
||||||
|
|
||||||
_dev: boolean | void;
|
_dev: boolean | void;
|
||||||
_inlineSourceMap: string | void;
|
_inlineSourceMap: string | void;
|
||||||
_minify: boolean | void;
|
_minify: boolean | void;
|
||||||
|
@ -51,13 +51,21 @@ class Bundle extends BundleBase {
|
||||||
_sourceMapUrl: ?string;
|
_sourceMapUrl: ?string;
|
||||||
postProcessBundleSourcemap: PostProcessBundleSourcemap;
|
postProcessBundleSourcemap: PostProcessBundleSourcemap;
|
||||||
|
|
||||||
constructor({sourceMapUrl, dev, minify, ramGroups, postProcessBundleSourcemap}: {
|
constructor(
|
||||||
sourceMapUrl: ?string,
|
{
|
||||||
dev?: boolean,
|
sourceMapUrl,
|
||||||
minify?: boolean,
|
dev,
|
||||||
ramGroups?: Array<string>,
|
minify,
|
||||||
postProcessBundleSourcemap: PostProcessBundleSourcemap,
|
ramGroups,
|
||||||
} = {}) {
|
postProcessBundleSourcemap,
|
||||||
|
}: {
|
||||||
|
sourceMapUrl: ?string,
|
||||||
|
dev?: boolean,
|
||||||
|
minify?: boolean,
|
||||||
|
ramGroups?: Array<string>,
|
||||||
|
postProcessBundleSourcemap: PostProcessBundleSourcemap,
|
||||||
|
} = {},
|
||||||
|
) {
|
||||||
super();
|
super();
|
||||||
this._sourceMap = null;
|
this._sourceMap = null;
|
||||||
this._sourceMapFormat = 'undetermined';
|
this._sourceMapFormat = 'undetermined';
|
||||||
|
@ -86,39 +94,44 @@ class Bundle extends BundleBase {
|
||||||
/* $FlowFixMe: erroneous change of signature. */
|
/* $FlowFixMe: erroneous change of signature. */
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const index = super.addModule(moduleTransport);
|
const index = super.addModule(moduleTransport);
|
||||||
return resolver.wrapModule({
|
return resolver
|
||||||
resolutionResponse,
|
.wrapModule({
|
||||||
module,
|
resolutionResponse,
|
||||||
name: moduleTransport.name,
|
module,
|
||||||
code: moduleTransport.code,
|
name: moduleTransport.name,
|
||||||
map: moduleTransport.map,
|
code: moduleTransport.code,
|
||||||
meta: moduleTransport.meta,
|
map: moduleTransport.map,
|
||||||
minify: this._minify,
|
meta: moduleTransport.meta,
|
||||||
dev: this._dev,
|
minify: this._minify,
|
||||||
}).then(({code, map}) => {
|
dev: this._dev,
|
||||||
// If we get a map from the transformer we'll switch to a mode
|
})
|
||||||
// were we're combining the source maps as opposed to
|
.then(({code, map}) => {
|
||||||
if (map) {
|
// If we get a map from the transformer we'll switch to a mode
|
||||||
const usesRawMappings = isRawMappings(map);
|
// were we're combining the source maps as opposed to
|
||||||
|
if (map) {
|
||||||
|
const usesRawMappings = isRawMappings(map);
|
||||||
|
|
||||||
if (this._sourceMapFormat === 'undetermined') {
|
if (this._sourceMapFormat === 'undetermined') {
|
||||||
this._sourceMapFormat = usesRawMappings ? 'flattened' : 'indexed';
|
this._sourceMapFormat = usesRawMappings ? 'flattened' : 'indexed';
|
||||||
} else if (usesRawMappings && this._sourceMapFormat === 'indexed') {
|
} else if (usesRawMappings && this._sourceMapFormat === 'indexed') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Got at least one module with a full source map, but ${
|
`Got at least one module with a full source map, but ${moduleTransport.sourcePath} has raw mappings`,
|
||||||
moduleTransport.sourcePath} has raw mappings`
|
);
|
||||||
);
|
} else if (
|
||||||
} else if (!usesRawMappings && this._sourceMapFormat === 'flattened') {
|
!usesRawMappings &&
|
||||||
throw new Error(
|
this._sourceMapFormat === 'flattened'
|
||||||
`Got at least one module with raw mappings, but ${
|
) {
|
||||||
moduleTransport.sourcePath} has a full source map`
|
throw new Error(
|
||||||
);
|
`Got at least one module with raw mappings, but ${moduleTransport.sourcePath} has a full source map`,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.replaceModuleAt(
|
this.replaceModuleAt(
|
||||||
index, new ModuleTransport({...moduleTransport, code, map}));
|
index,
|
||||||
});
|
new ModuleTransport({...moduleTransport, code, map}),
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
finalize(options: FinalizeOptions) {
|
finalize(options: FinalizeOptions) {
|
||||||
|
@ -138,15 +151,17 @@ class Bundle extends BundleBase {
|
||||||
_addRequireCall(moduleId: string) {
|
_addRequireCall(moduleId: string) {
|
||||||
const code = `;require(${JSON.stringify(moduleId)});`;
|
const code = `;require(${JSON.stringify(moduleId)});`;
|
||||||
const name = 'require-' + moduleId;
|
const name = 'require-' + moduleId;
|
||||||
super.addModule(new ModuleTransport({
|
super.addModule(
|
||||||
name,
|
new ModuleTransport({
|
||||||
id: -this._numRequireCalls - 1,
|
name,
|
||||||
code,
|
id: -this._numRequireCalls - 1,
|
||||||
virtual: true,
|
code,
|
||||||
sourceCode: code,
|
virtual: true,
|
||||||
sourcePath: name + '.js',
|
sourceCode: code,
|
||||||
meta: {preloaded: true},
|
sourcePath: name + '.js',
|
||||||
}));
|
meta: {preloaded: true},
|
||||||
|
}),
|
||||||
|
);
|
||||||
this._numRequireCalls += 1;
|
this._numRequireCalls += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +206,11 @@ class Bundle extends BundleBase {
|
||||||
lazyModules,
|
lazyModules,
|
||||||
get groups() {
|
get groups() {
|
||||||
if (!groups) {
|
if (!groups) {
|
||||||
groups = createRamBundleGroups(ramGroups || [], lazyModules, subtree);
|
groups = createRamBundleGroups(
|
||||||
|
ramGroups || [],
|
||||||
|
lazyModules,
|
||||||
|
subtree,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return groups;
|
return groups;
|
||||||
},
|
},
|
||||||
|
@ -226,10 +245,10 @@ class Bundle extends BundleBase {
|
||||||
!Array.isArray(module.map),
|
!Array.isArray(module.map),
|
||||||
`Unexpected raw mappings for ${module.sourcePath}`,
|
`Unexpected raw mappings for ${module.sourcePath}`,
|
||||||
);
|
);
|
||||||
let map: SourceMap = module.map == null || module.virtual
|
let map: SourceMap =
|
||||||
? generateSourceMapForVirtualModule(module)
|
module.map == null || module.virtual
|
||||||
: module.map;
|
? generateSourceMapForVirtualModule(module)
|
||||||
|
: module.map;
|
||||||
|
|
||||||
if (options.excludeSource && isMappingsMap(map)) {
|
if (options.excludeSource && isMappingsMap(map)) {
|
||||||
map = {...map, sourcesContent: []};
|
map = {...map, sourcesContent: []};
|
||||||
|
@ -287,10 +306,12 @@ class Bundle extends BundleBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
getJSModulePaths() {
|
getJSModulePaths() {
|
||||||
return this.getModules()
|
return (
|
||||||
// Filter out non-js files. Like images etc.
|
this.getModules()
|
||||||
.filter(module => !module.virtual)
|
// Filter out non-js files. Like images etc.
|
||||||
.map(module => module.sourcePath);
|
.filter(module => !module.virtual)
|
||||||
|
.map(module => module.sourcePath)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDebugInfo() {
|
getDebugInfo() {
|
||||||
|
@ -308,11 +329,18 @@ class Bundle extends BundleBase {
|
||||||
'}',
|
'}',
|
||||||
'</style>',
|
'</style>',
|
||||||
'<h3> Module paths and transformed code: </h3>',
|
'<h3> Module paths and transformed code: </h3>',
|
||||||
this.getModules().map(function(m) {
|
this.getModules()
|
||||||
return '<div> <h4> Path: </h4>' + m.sourcePath + '<br/> <h4> Source: </h4>' +
|
.map(function(m) {
|
||||||
'<code><pre class="collapsed" onclick="this.classList.remove(\'collapsed\')">' +
|
return (
|
||||||
_.escape(m.code) + '</pre></code></div>';
|
'<div> <h4> Path: </h4>' +
|
||||||
}).join('\n'),
|
m.sourcePath +
|
||||||
|
'<br/> <h4> Source: </h4>' +
|
||||||
|
'<code><pre class="collapsed" onclick="this.classList.remove(\'collapsed\')">' +
|
||||||
|
_.escape(m.code) +
|
||||||
|
'</pre></code></div>'
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.join('\n'),
|
||||||
].join('\n');
|
].join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +354,7 @@ function generateSourceMapForVirtualModule(module): MappingsMap {
|
||||||
let mappings = 'AAAA;';
|
let mappings = 'AAAA;';
|
||||||
|
|
||||||
for (let i = 1; i < module.code.split('\n').length; i++) {
|
for (let i = 1; i < module.code.split('\n').length; i++) {
|
||||||
mappings += 'AACA;';
|
mappings += 'AACA;';
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -350,7 +378,7 @@ function partition(array, predicate) {
|
||||||
return [included, excluded];
|
return [included, excluded];
|
||||||
}
|
}
|
||||||
|
|
||||||
function * subtree(
|
function* subtree(
|
||||||
moduleTransport: ModuleTransport,
|
moduleTransport: ModuleTransport,
|
||||||
moduleTransportsByPath: Map<string, ModuleTransport>,
|
moduleTransportsByPath: Map<string, ModuleTransport>,
|
||||||
seen = new Set(),
|
seen = new Set(),
|
||||||
|
@ -359,13 +387,14 @@ function * subtree(
|
||||||
const {meta} = moduleTransport;
|
const {meta} = moduleTransport;
|
||||||
invariant(
|
invariant(
|
||||||
meta != null,
|
meta != null,
|
||||||
'Unexpected module transport without meta information: ' + moduleTransport.sourcePath,
|
'Unexpected module transport without meta information: ' +
|
||||||
|
moduleTransport.sourcePath,
|
||||||
);
|
);
|
||||||
for (const [, {path}] of meta.dependencyPairs || []) {
|
for (const [, {path}] of meta.dependencyPairs || []) {
|
||||||
const dependency = moduleTransportsByPath.get(path);
|
const dependency = moduleTransportsByPath.get(path);
|
||||||
if (dependency && !seen.has(dependency.id)) {
|
if (dependency && !seen.has(dependency.id)) {
|
||||||
yield dependency.id;
|
yield dependency.id;
|
||||||
yield * subtree(dependency, moduleTransportsByPath, seen);
|
yield* subtree(dependency, moduleTransportsByPath, seen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @flow
|
* @flow
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const ModuleTransport = require('../lib/ModuleTransport');
|
const ModuleTransport = require('../lib/ModuleTransport');
|
||||||
|
@ -24,7 +26,6 @@ export type GetSourceOptions = {
|
||||||
};
|
};
|
||||||
|
|
||||||
class BundleBase {
|
class BundleBase {
|
||||||
|
|
||||||
_assets: Array<mixed>;
|
_assets: Array<mixed>;
|
||||||
_finalized: boolean;
|
_finalized: boolean;
|
||||||
_mainModuleId: number | void;
|
_mainModuleId: number | void;
|
||||||
|
@ -104,7 +105,9 @@ class BundleBase {
|
||||||
|
|
||||||
assertFinalized(message?: string) {
|
assertFinalized(message?: string) {
|
||||||
if (!this._finalized) {
|
if (!this._finalized) {
|
||||||
throw new Error(message || 'Bundle needs to be finalized before getting any source');
|
throw new Error(
|
||||||
|
message || 'Bundle needs to be finalized before getting any source',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
*
|
*
|
||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Bundle = require('../Bundle');
|
const Bundle = require('../Bundle');
|
||||||
|
|
|
@ -5,7 +5,10 @@
|
||||||
* This source code is licensed under the BSD-style license found in the
|
* This source code is licensed under the BSD-style license found in the
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
jest
|
jest
|
||||||
|
@ -23,8 +26,7 @@ jest
|
||||||
.mock('../Bundle')
|
.mock('../Bundle')
|
||||||
.mock('../HMRBundle')
|
.mock('../HMRBundle')
|
||||||
.mock('../../Logger')
|
.mock('../../Logger')
|
||||||
.mock('/path/to/transformer.js', () => ({}), {virtual: true})
|
.mock('/path/to/transformer.js', () => ({}), {virtual: true});
|
||||||
;
|
|
||||||
|
|
||||||
var Bundler = require('../');
|
var Bundler = require('../');
|
||||||
var Resolver = require('../../Resolver');
|
var Resolver = require('../../Resolver');
|
||||||
|
@ -36,7 +38,6 @@ const path = require('path');
|
||||||
|
|
||||||
const {any, objectContaining} = expect;
|
const {any, objectContaining} = expect;
|
||||||
|
|
||||||
|
|
||||||
var commonOptions = {
|
var commonOptions = {
|
||||||
allowBundleUpdates: false,
|
allowBundleUpdates: false,
|
||||||
assetExts: defaults.assetExts,
|
assetExts: defaults.assetExts,
|
||||||
|
@ -52,7 +53,6 @@ var commonOptions = {
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Bundler', function() {
|
describe('Bundler', function() {
|
||||||
|
|
||||||
function createModule({
|
function createModule({
|
||||||
path,
|
path,
|
||||||
id,
|
id,
|
||||||
|
@ -100,10 +100,12 @@ describe('Bundler', function() {
|
||||||
getModuleSystemDependencies,
|
getModuleSystemDependencies,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
Resolver.load = jest.fn().mockImplementation(opts => Promise.resolve(new Resolver(opts)));
|
Resolver.load = jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(opts => Promise.resolve(new Resolver(opts)));
|
||||||
|
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'path': {'to': {'transformer.js': ''}},
|
path: {to: {'transformer.js': ''}},
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.statSync.mockImplementation(function() {
|
fs.statSync.mockImplementation(function() {
|
||||||
|
@ -151,7 +153,7 @@ describe('Bundler', function() {
|
||||||
options: transformOptions,
|
options: transformOptions,
|
||||||
getModuleId: () => 123,
|
getModuleId: () => 123,
|
||||||
getResolvedDependencyPairs: () => [],
|
getResolvedDependencyPairs: () => [],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
getModuleSystemDependencies.mockImplementation(function() {
|
getModuleSystemDependencies.mockImplementation(function() {
|
||||||
|
@ -188,12 +190,17 @@ describe('Bundler', function() {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows overriding the platforms array', () => {
|
it('allows overriding the platforms array', () => {
|
||||||
expect(bundler._opts.platforms).toEqual(['ios', 'android', 'windows', 'web']);
|
expect(bundler._opts.platforms).toEqual([
|
||||||
|
'ios',
|
||||||
|
'android',
|
||||||
|
'windows',
|
||||||
|
'web',
|
||||||
|
]);
|
||||||
const b = new Bundler({
|
const b = new Bundler({
|
||||||
...commonOptions,
|
...commonOptions,
|
||||||
projectRoots,
|
projectRoots,
|
||||||
|
@ -217,96 +224,115 @@ describe('Bundler', function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
assetServer.getAssetData
|
assetServer.getAssetData.mockImplementation(() =>
|
||||||
.mockImplementation(() => Promise.resolve(mockAsset));
|
Promise.resolve(mockAsset),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates a bundle', function() {
|
it('creates a bundle', function() {
|
||||||
return bundler.bundle({
|
return bundler
|
||||||
entryFile: '/root/foo.js',
|
.bundle({
|
||||||
runBeforeMainModule: [],
|
entryFile: '/root/foo.js',
|
||||||
runModule: true,
|
|
||||||
sourceMapUrl: 'source_map_url',
|
|
||||||
}).then(bundle => {
|
|
||||||
const ithAddedModule = i => bundle.addModule.mock.calls[i][2].path;
|
|
||||||
|
|
||||||
expect(ithAddedModule(0)).toEqual('/root/foo.js');
|
|
||||||
expect(ithAddedModule(1)).toEqual('/root/bar.js');
|
|
||||||
expect(ithAddedModule(2)).toEqual('/root/img/new_image.png');
|
|
||||||
expect(ithAddedModule(3)).toEqual('/root/file.json');
|
|
||||||
|
|
||||||
expect(bundle.finalize.mock.calls[0]).toEqual([{
|
|
||||||
runModule: true,
|
|
||||||
runBeforeMainModule: [],
|
runBeforeMainModule: [],
|
||||||
allowUpdates: false,
|
runModule: true,
|
||||||
}]);
|
sourceMapUrl: 'source_map_url',
|
||||||
|
})
|
||||||
|
.then(bundle => {
|
||||||
|
const ithAddedModule = i => bundle.addModule.mock.calls[i][2].path;
|
||||||
|
|
||||||
expect(bundle.addAsset.mock.calls[0]).toEqual([{
|
expect(ithAddedModule(0)).toEqual('/root/foo.js');
|
||||||
__packager_asset: true,
|
expect(ithAddedModule(1)).toEqual('/root/bar.js');
|
||||||
fileSystemLocation: '/root/img',
|
expect(ithAddedModule(2)).toEqual('/root/img/new_image.png');
|
||||||
httpServerLocation: '/assets/img',
|
expect(ithAddedModule(3)).toEqual('/root/file.json');
|
||||||
width: 50,
|
|
||||||
height: 100,
|
|
||||||
scales: [1, 2, 3],
|
|
||||||
files: [
|
|
||||||
'/root/img/img.png',
|
|
||||||
'/root/img/img@2x.png',
|
|
||||||
'/root/img/img@3x.png',
|
|
||||||
],
|
|
||||||
hash: 'i am a hash',
|
|
||||||
name: 'img',
|
|
||||||
type: 'png',
|
|
||||||
}]);
|
|
||||||
|
|
||||||
// TODO(amasad) This fails with 0 != 5 in OSS
|
expect(bundle.finalize.mock.calls[0]).toEqual([
|
||||||
//expect(ProgressBar.prototype.tick.mock.calls.length).toEqual(modules.length);
|
{
|
||||||
});
|
runModule: true,
|
||||||
|
runBeforeMainModule: [],
|
||||||
|
allowUpdates: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(bundle.addAsset.mock.calls[0]).toEqual([
|
||||||
|
{
|
||||||
|
__packager_asset: true,
|
||||||
|
fileSystemLocation: '/root/img',
|
||||||
|
httpServerLocation: '/assets/img',
|
||||||
|
width: 50,
|
||||||
|
height: 100,
|
||||||
|
scales: [1, 2, 3],
|
||||||
|
files: [
|
||||||
|
'/root/img/img.png',
|
||||||
|
'/root/img/img@2x.png',
|
||||||
|
'/root/img/img@3x.png',
|
||||||
|
],
|
||||||
|
hash: 'i am a hash',
|
||||||
|
name: 'img',
|
||||||
|
type: 'png',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// TODO(amasad) This fails with 0 != 5 in OSS
|
||||||
|
//expect(ProgressBar.prototype.tick.mock.calls.length).toEqual(modules.length);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('loads and runs asset plugins', function() {
|
it('loads and runs asset plugins', function() {
|
||||||
jest.mock('mockPlugin1', () => {
|
jest.mock(
|
||||||
return asset => {
|
'mockPlugin1',
|
||||||
asset.extraReverseHash = asset.hash.split('').reverse().join('');
|
() => {
|
||||||
return asset;
|
return asset => {
|
||||||
};
|
asset.extraReverseHash = asset.hash.split('').reverse().join('');
|
||||||
}, {virtual: true});
|
return asset;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{virtual: true},
|
||||||
|
);
|
||||||
|
|
||||||
jest.mock('asyncMockPlugin2', () => {
|
jest.mock(
|
||||||
return asset => {
|
'asyncMockPlugin2',
|
||||||
expect(asset.extraReverseHash).toBeDefined();
|
() => {
|
||||||
return new Promise(resolve => {
|
return asset => {
|
||||||
asset.extraPixelCount = asset.width * asset.height;
|
expect(asset.extraReverseHash).toBeDefined();
|
||||||
resolve(asset);
|
return new Promise(resolve => {
|
||||||
});
|
asset.extraPixelCount = asset.width * asset.height;
|
||||||
};
|
resolve(asset);
|
||||||
}, {virtual: true});
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{virtual: true},
|
||||||
|
);
|
||||||
|
|
||||||
return bundler.bundle({
|
return bundler
|
||||||
entryFile: '/root/foo.js',
|
.bundle({
|
||||||
runBeforeMainModule: [],
|
entryFile: '/root/foo.js',
|
||||||
runModule: true,
|
runBeforeMainModule: [],
|
||||||
sourceMapUrl: 'source_map_url',
|
runModule: true,
|
||||||
assetPlugins: ['mockPlugin1', 'asyncMockPlugin2'],
|
sourceMapUrl: 'source_map_url',
|
||||||
}).then(bundle => {
|
assetPlugins: ['mockPlugin1', 'asyncMockPlugin2'],
|
||||||
expect(bundle.addAsset.mock.calls[0]).toEqual([{
|
})
|
||||||
__packager_asset: true,
|
.then(bundle => {
|
||||||
fileSystemLocation: '/root/img',
|
expect(bundle.addAsset.mock.calls[0]).toEqual([
|
||||||
httpServerLocation: '/assets/img',
|
{
|
||||||
width: 50,
|
__packager_asset: true,
|
||||||
height: 100,
|
fileSystemLocation: '/root/img',
|
||||||
scales: [1, 2, 3],
|
httpServerLocation: '/assets/img',
|
||||||
files: [
|
width: 50,
|
||||||
'/root/img/img.png',
|
height: 100,
|
||||||
'/root/img/img@2x.png',
|
scales: [1, 2, 3],
|
||||||
'/root/img/img@3x.png',
|
files: [
|
||||||
],
|
'/root/img/img.png',
|
||||||
hash: 'i am a hash',
|
'/root/img/img@2x.png',
|
||||||
name: 'img',
|
'/root/img/img@3x.png',
|
||||||
type: 'png',
|
],
|
||||||
extraReverseHash: 'hsah a ma i',
|
hash: 'i am a hash',
|
||||||
extraPixelCount: 5000,
|
name: 'img',
|
||||||
}]);
|
type: 'png',
|
||||||
});
|
extraReverseHash: 'hsah a ma i',
|
||||||
|
extraPixelCount: 5000,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls the module post-processing function', () => {
|
it('calls the module post-processing function', () => {
|
||||||
|
@ -324,34 +350,39 @@ describe('Bundler', function() {
|
||||||
const platform = 'arbitrary';
|
const platform = 'arbitrary';
|
||||||
|
|
||||||
const entryFile = '/root/foo.js';
|
const entryFile = '/root/foo.js';
|
||||||
return b.bundle({
|
return b
|
||||||
dev,
|
.bundle({
|
||||||
entryFile,
|
dev,
|
||||||
minify,
|
entryFile,
|
||||||
platform,
|
minify,
|
||||||
runBeforeMainModule: [],
|
platform,
|
||||||
runModule: true,
|
runBeforeMainModule: [],
|
||||||
sourceMapUrl: 'source_map_url',
|
runModule: true,
|
||||||
}).then(() => {
|
sourceMapUrl: 'source_map_url',
|
||||||
expect(postProcessModules)
|
})
|
||||||
.toBeCalledWith(
|
.then(() => {
|
||||||
modules.map(x => objectContaining({
|
expect(postProcessModules).toBeCalledWith(
|
||||||
name: any(String),
|
modules.map(x =>
|
||||||
id: any(Number),
|
objectContaining({
|
||||||
code: any(String),
|
name: any(String),
|
||||||
sourceCode: any(String),
|
id: any(Number),
|
||||||
sourcePath: x.path,
|
code: any(String),
|
||||||
meta: any(Object),
|
sourceCode: any(String),
|
||||||
polyfill: !!x.isPolyfill(),
|
sourcePath: x.path,
|
||||||
})),
|
meta: any(Object),
|
||||||
|
polyfill: !!x.isPolyfill(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
entryFile,
|
entryFile,
|
||||||
{dev, minify, platform},
|
{dev, minify, platform},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('respects the order of modules returned by the post-processing function', () => {
|
it('respects the order of modules returned by the post-processing function', () => {
|
||||||
const postProcessModules = jest.fn().mockImplementation((ms, e) => ms.reverse());
|
const postProcessModules = jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation((ms, e) => ms.reverse());
|
||||||
|
|
||||||
const b = new Bundler({
|
const b = new Bundler({
|
||||||
...commonOptions,
|
...commonOptions,
|
||||||
|
@ -361,21 +392,23 @@ describe('Bundler', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
const entryFile = '/root/foo.js';
|
const entryFile = '/root/foo.js';
|
||||||
return b.bundle({
|
return b
|
||||||
entryFile,
|
.bundle({
|
||||||
runBeforeMainModule: [],
|
entryFile,
|
||||||
runModule: true,
|
runBeforeMainModule: [],
|
||||||
sourceMapUrl: 'source_map_url',
|
runModule: true,
|
||||||
}).then(bundle => {
|
sourceMapUrl: 'source_map_url',
|
||||||
const ithAddedModule = i => bundle.addModule.mock.calls[i][2].path;
|
})
|
||||||
|
.then(bundle => {
|
||||||
|
const ithAddedModule = i => bundle.addModule.mock.calls[i][2].path;
|
||||||
|
|
||||||
[
|
[
|
||||||
'/root/file.json',
|
'/root/file.json',
|
||||||
'/root/img/new_image.png',
|
'/root/img/new_image.png',
|
||||||
'/root/bar.js',
|
'/root/bar.js',
|
||||||
'/root/foo.js',
|
'/root/foo.js',
|
||||||
].forEach((path, ix) => expect(ithAddedModule(ix)).toEqual(path));
|
].forEach((path, ix) => expect(ithAddedModule(ix)).toEqual(path));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -423,18 +456,21 @@ describe('Bundler', function() {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return bundler.getOrderedDependencyPaths('/root/foo.js', true)
|
return bundler
|
||||||
.then(paths => expect(paths).toEqual([
|
.getOrderedDependencyPaths('/root/foo.js', true)
|
||||||
'/root/foo.js',
|
.then(paths =>
|
||||||
'/root/bar.js',
|
expect(paths).toEqual([
|
||||||
'/root/img/new_image.png',
|
'/root/foo.js',
|
||||||
'/root/img/new_image@2x.png',
|
'/root/bar.js',
|
||||||
'/root/img/new_image@3x.png',
|
'/root/img/new_image.png',
|
||||||
'/root/file.json',
|
'/root/img/new_image@2x.png',
|
||||||
'/root/img/new_image2.png',
|
'/root/img/new_image@3x.png',
|
||||||
'/root/img/new_image2@2x.png',
|
'/root/file.json',
|
||||||
'/root/img/new_image2@3x.png',
|
'/root/img/new_image2.png',
|
||||||
]));
|
'/root/img/new_image2@2x.png',
|
||||||
|
'/root/img/new_image2@3x.png',
|
||||||
|
]),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @flow
|
* @flow
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
@ -68,7 +69,7 @@ export type GetTransformOptionsOpts = {|
|
||||||
export type GetTransformOptions = (
|
export type GetTransformOptions = (
|
||||||
mainModuleName: string,
|
mainModuleName: string,
|
||||||
options: GetTransformOptionsOpts,
|
options: GetTransformOptionsOpts,
|
||||||
getDependenciesOf: string => Promise<Array<string>>,
|
getDependenciesOf: (string) => Promise<Array<string>>,
|
||||||
) => Promise<ExtraTransformOptions>;
|
) => Promise<ExtraTransformOptions>;
|
||||||
|
|
||||||
export type AssetDescriptor = {
|
export type AssetDescriptor = {
|
||||||
|
@ -152,7 +153,6 @@ type Options = {|
|
||||||
const {hasOwnProperty} = Object;
|
const {hasOwnProperty} = Object;
|
||||||
|
|
||||||
class Bundler {
|
class Bundler {
|
||||||
|
|
||||||
_opts: Options;
|
_opts: Options;
|
||||||
_getModuleId: (opts: Module) => number;
|
_getModuleId: (opts: Module) => number;
|
||||||
_transformer: Transformer;
|
_transformer: Transformer;
|
||||||
|
@ -167,14 +167,16 @@ class Bundler {
|
||||||
opts.projectRoots.forEach(verifyRootExists);
|
opts.projectRoots.forEach(verifyRootExists);
|
||||||
|
|
||||||
const transformModuleStr = fs.readFileSync(opts.transformModulePath);
|
const transformModuleStr = fs.readFileSync(opts.transformModulePath);
|
||||||
const transformModuleHash =
|
const transformModuleHash = crypto
|
||||||
crypto.createHash('sha1').update(transformModuleStr).digest('hex');
|
.createHash('sha1')
|
||||||
|
.update(transformModuleStr)
|
||||||
|
.digest('hex');
|
||||||
|
|
||||||
const stableProjectRoots = opts.projectRoots.map(p => {
|
const stableProjectRoots = opts.projectRoots.map(p => {
|
||||||
return path.relative(path.join(__dirname, '../../../..'), p);
|
return path.relative(path.join(__dirname, '../../../..'), p);
|
||||||
});
|
});
|
||||||
|
|
||||||
const cacheKeyParts = [
|
const cacheKeyParts = [
|
||||||
'react-packager-cache',
|
'react-packager-cache',
|
||||||
VERSION,
|
VERSION,
|
||||||
opts.cacheVersion,
|
opts.cacheVersion,
|
||||||
|
@ -193,17 +195,20 @@ class Bundler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const transformCacheKey = crypto.createHash('sha1').update(
|
const transformCacheKey = crypto
|
||||||
cacheKeyParts.join('$'),
|
.createHash('sha1')
|
||||||
).digest('hex');
|
.update(cacheKeyParts.join('$'))
|
||||||
|
.digest('hex');
|
||||||
|
|
||||||
debug(`Using transform cache key "${transformCacheKey}"`);
|
debug(`Using transform cache key "${transformCacheKey}"`);
|
||||||
this._transformer = new Transformer(
|
this._transformer = new Transformer(
|
||||||
opts.transformModulePath,
|
opts.transformModulePath,
|
||||||
opts.maxWorkers,
|
opts.maxWorkers,
|
||||||
{
|
{
|
||||||
stdoutChunk: chunk => opts.reporter.update({type: 'worker_stdout_chunk', chunk}),
|
stdoutChunk: chunk =>
|
||||||
stderrChunk: chunk => opts.reporter.update({type: 'worker_stderr_chunk', chunk}),
|
opts.reporter.update({type: 'worker_stdout_chunk', chunk}),
|
||||||
|
stderrChunk: chunk =>
|
||||||
|
opts.reporter.update({type: 'worker_stderr_chunk', chunk}),
|
||||||
},
|
},
|
||||||
opts.workerPath,
|
opts.workerPath,
|
||||||
);
|
);
|
||||||
|
@ -232,8 +237,8 @@ class Bundler {
|
||||||
reporter: opts.reporter,
|
reporter: opts.reporter,
|
||||||
resetCache: opts.resetCache,
|
resetCache: opts.resetCache,
|
||||||
sourceExts: opts.sourceExts,
|
sourceExts: opts.sourceExts,
|
||||||
transformCode:
|
transformCode: (module, code, transformCodeOptions) =>
|
||||||
(module, code, transformCodeOptions) => this._transformer.transformFile(
|
this._transformer.transformFile(
|
||||||
module.path,
|
module.path,
|
||||||
module.localPath,
|
module.localPath,
|
||||||
code,
|
code,
|
||||||
|
@ -251,8 +256,8 @@ class Bundler {
|
||||||
|
|
||||||
end() {
|
end() {
|
||||||
this._transformer.kill();
|
this._transformer.kill();
|
||||||
return this._resolverPromise.then(
|
return this._resolverPromise.then(resolver =>
|
||||||
resolver => resolver.getDependencyGraph().getWatcher().end(),
|
resolver.getDependencyGraph().getWatcher().end(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,41 +269,40 @@ class Bundler {
|
||||||
}): Promise<Bundle> {
|
}): Promise<Bundle> {
|
||||||
const {dev, minify, unbundle} = options;
|
const {dev, minify, unbundle} = options;
|
||||||
const postProcessBundleSourcemap = this._opts.postProcessBundleSourcemap;
|
const postProcessBundleSourcemap = this._opts.postProcessBundleSourcemap;
|
||||||
return this._resolverPromise.then(
|
return this._resolverPromise
|
||||||
resolver => resolver.getModuleSystemDependencies({dev, unbundle}),
|
.then(resolver => resolver.getModuleSystemDependencies({dev, unbundle}))
|
||||||
).then(moduleSystemDeps => this._bundle({
|
.then(moduleSystemDeps =>
|
||||||
...options,
|
this._bundle({
|
||||||
bundle: new Bundle({
|
...options,
|
||||||
dev,
|
bundle: new Bundle({
|
||||||
minify,
|
dev,
|
||||||
sourceMapUrl: options.sourceMapUrl,
|
minify,
|
||||||
postProcessBundleSourcemap,
|
sourceMapUrl: options.sourceMapUrl,
|
||||||
}),
|
postProcessBundleSourcemap,
|
||||||
moduleSystemDeps,
|
}),
|
||||||
}));
|
moduleSystemDeps,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_sourceHMRURL(platform: ?string, hmrpath: string) {
|
_sourceHMRURL(platform: ?string, hmrpath: string) {
|
||||||
return this._hmrURL(
|
return this._hmrURL('', platform, 'bundle', hmrpath);
|
||||||
'',
|
|
||||||
platform,
|
|
||||||
'bundle',
|
|
||||||
hmrpath,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_sourceMappingHMRURL(platform: ?string, hmrpath: string) {
|
_sourceMappingHMRURL(platform: ?string, hmrpath: string) {
|
||||||
// Chrome expects `sourceURL` when eval'ing code
|
// Chrome expects `sourceURL` when eval'ing code
|
||||||
return this._hmrURL(
|
return this._hmrURL('//# sourceURL=', platform, 'map', hmrpath);
|
||||||
'\/\/# sourceURL=',
|
|
||||||
platform,
|
|
||||||
'map',
|
|
||||||
hmrpath,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_hmrURL(prefix: string, platform: ?string, extensionOverride: string, filePath: string) {
|
_hmrURL(
|
||||||
const matchingRoot = this._projectRoots.find(root => filePath.startsWith(root));
|
prefix: string,
|
||||||
|
platform: ?string,
|
||||||
|
extensionOverride: string,
|
||||||
|
filePath: string,
|
||||||
|
) {
|
||||||
|
const matchingRoot = this._projectRoots.find(root =>
|
||||||
|
filePath.startsWith(root),
|
||||||
|
);
|
||||||
|
|
||||||
if (!matchingRoot) {
|
if (!matchingRoot) {
|
||||||
throw new Error('No matching project root for ' + filePath);
|
throw new Error('No matching project root for ' + filePath);
|
||||||
|
@ -316,13 +320,22 @@ class Bundler {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
prefix + resource +
|
prefix +
|
||||||
'.' + extensionOverride + '?' +
|
resource +
|
||||||
'platform=' + (platform || '') + '&runModule=false&entryModuleOnly=true&hot=true'
|
'.' +
|
||||||
|
extensionOverride +
|
||||||
|
'?' +
|
||||||
|
'platform=' +
|
||||||
|
(platform || '') +
|
||||||
|
'&runModule=false&entryModuleOnly=true&hot=true'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
hmrBundle(options: {platform: ?string}, host: string, port: number): Promise<HMRBundle> {
|
hmrBundle(
|
||||||
|
options: {platform: ?string},
|
||||||
|
host: string,
|
||||||
|
port: number,
|
||||||
|
): Promise<HMRBundle> {
|
||||||
return this._bundle({
|
return this._bundle({
|
||||||
...options,
|
...options,
|
||||||
bundle: new HMRBundle({
|
bundle: new HMRBundle({
|
||||||
|
@ -372,43 +385,54 @@ class Bundler {
|
||||||
runModule?: boolean,
|
runModule?: boolean,
|
||||||
unbundle?: boolean,
|
unbundle?: boolean,
|
||||||
}) {
|
}) {
|
||||||
const onResolutionResponse = (response: ResolutionResponse<Module, BundlingOptions>) => {
|
const onResolutionResponse = (
|
||||||
|
response: ResolutionResponse<Module, BundlingOptions>,
|
||||||
|
) => {
|
||||||
/* $FlowFixMe: looks like ResolutionResponse is monkey-patched
|
/* $FlowFixMe: looks like ResolutionResponse is monkey-patched
|
||||||
* with `getModuleId`. */
|
* with `getModuleId`. */
|
||||||
bundle.setMainModuleId(response.getModuleId(getMainModule(response)));
|
bundle.setMainModuleId(response.getModuleId(getMainModule(response)));
|
||||||
if (entryModuleOnly && entryFile) {
|
if (entryModuleOnly && entryFile) {
|
||||||
response.dependencies = response.dependencies.filter(module =>
|
response.dependencies = response.dependencies.filter(module =>
|
||||||
module.path.endsWith(entryFile || '')
|
module.path.endsWith(entryFile || ''),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
response.dependencies = moduleSystemDeps.concat(response.dependencies);
|
response.dependencies = moduleSystemDeps.concat(response.dependencies);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const finalizeBundle = ({bundle: finalBundle, transformedModules, response, modulesByName}: {
|
const finalizeBundle = ({
|
||||||
|
bundle: finalBundle,
|
||||||
|
transformedModules,
|
||||||
|
response,
|
||||||
|
modulesByName,
|
||||||
|
}: {
|
||||||
bundle: Bundle,
|
bundle: Bundle,
|
||||||
transformedModules: Array<{module: Module, transformed: ModuleTransport}>,
|
transformedModules: Array<{module: Module, transformed: ModuleTransport}>,
|
||||||
response: ResolutionResponse<Module, BundlingOptions>,
|
response: ResolutionResponse<Module, BundlingOptions>,
|
||||||
modulesByName: {[name: string]: Module},
|
modulesByName: {[name: string]: Module},
|
||||||
}) =>
|
}) =>
|
||||||
this._resolverPromise.then(resolver => Promise.all(
|
this._resolverPromise
|
||||||
transformedModules.map(({module, transformed}) =>
|
.then(resolver =>
|
||||||
finalBundle.addModule(resolver, response, module, transformed)
|
Promise.all(
|
||||||
|
transformedModules.map(({module, transformed}) =>
|
||||||
|
finalBundle.addModule(resolver, response, module, transformed),
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)).then(() => {
|
.then(() => {
|
||||||
const runBeforeMainModuleIds = Array.isArray(runBeforeMainModule)
|
const runBeforeMainModuleIds = Array.isArray(runBeforeMainModule)
|
||||||
? runBeforeMainModule
|
? runBeforeMainModule
|
||||||
.map(name => modulesByName[name])
|
.map(name => modulesByName[name])
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.map(response.getModuleId)
|
.map(response.getModuleId)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
finalBundle.finalize({
|
finalBundle.finalize({
|
||||||
runModule,
|
runModule,
|
||||||
runBeforeMainModule: runBeforeMainModuleIds,
|
runBeforeMainModule: runBeforeMainModuleIds,
|
||||||
allowUpdates: this._opts.allowBundleUpdates,
|
allowUpdates: this._opts.allowBundleUpdates,
|
||||||
|
});
|
||||||
|
return finalBundle;
|
||||||
});
|
});
|
||||||
return finalBundle;
|
|
||||||
});
|
|
||||||
|
|
||||||
return this._buildBundle({
|
return this._buildBundle({
|
||||||
entryFile,
|
entryFile,
|
||||||
|
@ -445,12 +469,13 @@ class Bundler {
|
||||||
finalizeBundle = emptyFunction,
|
finalizeBundle = emptyFunction,
|
||||||
onProgress = emptyFunction,
|
onProgress = emptyFunction,
|
||||||
}: *) {
|
}: *) {
|
||||||
const transformingFilesLogEntry =
|
const transformingFilesLogEntry = log(
|
||||||
log(createActionStartEntry({
|
createActionStartEntry({
|
||||||
action_name: 'Transforming files',
|
action_name: 'Transforming files',
|
||||||
entry_point: entryFile,
|
entry_point: entryFile,
|
||||||
environment: dev ? 'dev' : 'prod',
|
environment: dev ? 'dev' : 'prod',
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const modulesByName = Object.create(null);
|
const modulesByName = Object.create(null);
|
||||||
|
|
||||||
|
@ -467,9 +492,10 @@ class Bundler {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all([
|
||||||
[this._resolverPromise, resolutionResponse],
|
this._resolverPromise,
|
||||||
).then(([resolver, response]) => {
|
resolutionResponse,
|
||||||
|
]).then(([resolver, response]) => {
|
||||||
bundle.setRamGroups(response.options.ramGroups);
|
bundle.setRamGroups(response.options.ramGroups);
|
||||||
|
|
||||||
log(createActionEndEntry(transformingFilesLogEntry));
|
log(createActionEndEntry(transformingFilesLogEntry));
|
||||||
|
@ -477,12 +503,15 @@ class Bundler {
|
||||||
|
|
||||||
// get entry file complete path (`entryFile` is a local path, i.e. relative to roots)
|
// get entry file complete path (`entryFile` is a local path, i.e. relative to roots)
|
||||||
let entryFilePath;
|
let entryFilePath;
|
||||||
if (response.dependencies.length > 1) { // skip HMR requests
|
if (response.dependencies.length > 1) {
|
||||||
const numModuleSystemDependencies =
|
// skip HMR requests
|
||||||
resolver.getModuleSystemDependencies({dev, unbundle}).length;
|
const numModuleSystemDependencies = resolver.getModuleSystemDependencies(
|
||||||
|
{dev, unbundle},
|
||||||
|
).length;
|
||||||
|
|
||||||
const dependencyIndex =
|
const dependencyIndex =
|
||||||
(response.numPrependedDependencies || 0) + numModuleSystemDependencies;
|
(response.numPrependedDependencies || 0) +
|
||||||
|
numModuleSystemDependencies;
|
||||||
|
|
||||||
if (dependencyIndex in response.dependencies) {
|
if (dependencyIndex in response.dependencies) {
|
||||||
entryFilePath = response.dependencies[dependencyIndex].path;
|
entryFilePath = response.dependencies[dependencyIndex].path;
|
||||||
|
@ -490,28 +519,27 @@ class Bundler {
|
||||||
}
|
}
|
||||||
|
|
||||||
const modulesByTransport: Map<ModuleTransport, Module> = new Map();
|
const modulesByTransport: Map<ModuleTransport, Module> = new Map();
|
||||||
const toModuleTransport: Module => Promise<ModuleTransport> =
|
const toModuleTransport: Module => Promise<ModuleTransport> = module =>
|
||||||
module =>
|
this._toModuleTransport({
|
||||||
this._toModuleTransport({
|
module,
|
||||||
|
bundle,
|
||||||
|
entryFilePath,
|
||||||
|
assetPlugins,
|
||||||
|
options: response.options,
|
||||||
|
/* $FlowFixMe: `getModuleId` is monkey-patched */
|
||||||
|
getModuleId: (response.getModuleId: () => number),
|
||||||
|
dependencyPairs: response.getResolvedDependencyPairs(module),
|
||||||
|
}).then(transformed => {
|
||||||
|
modulesByTransport.set(transformed, module);
|
||||||
|
modulesByName[transformed.name] = module;
|
||||||
|
onModuleTransformed({
|
||||||
module,
|
module,
|
||||||
|
response,
|
||||||
bundle,
|
bundle,
|
||||||
entryFilePath,
|
transformed,
|
||||||
assetPlugins,
|
|
||||||
options: response.options,
|
|
||||||
/* $FlowFixMe: `getModuleId` is monkey-patched */
|
|
||||||
getModuleId: (response.getModuleId: () => number),
|
|
||||||
dependencyPairs: response.getResolvedDependencyPairs(module),
|
|
||||||
}).then(transformed => {
|
|
||||||
modulesByTransport.set(transformed, module);
|
|
||||||
modulesByName[transformed.name] = module;
|
|
||||||
onModuleTransformed({
|
|
||||||
module,
|
|
||||||
response,
|
|
||||||
bundle,
|
|
||||||
transformed,
|
|
||||||
});
|
|
||||||
return transformed;
|
|
||||||
});
|
});
|
||||||
|
return transformed;
|
||||||
|
});
|
||||||
|
|
||||||
const p = this._opts.postProcessModules;
|
const p = this._opts.postProcessModules;
|
||||||
const postProcess = p
|
const postProcess = p
|
||||||
|
@ -525,8 +553,14 @@ class Bundler {
|
||||||
module: modulesByTransport.get(transformed),
|
module: modulesByTransport.get(transformed),
|
||||||
transformed,
|
transformed,
|
||||||
}));
|
}));
|
||||||
return finalizeBundle({bundle, transformedModules, response, modulesByName});
|
return finalizeBundle({
|
||||||
}).then(() => bundle);
|
bundle,
|
||||||
|
transformedModules,
|
||||||
|
response,
|
||||||
|
modulesByName,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(() => bundle);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,26 +579,25 @@ class Bundler {
|
||||||
hot?: boolean,
|
hot?: boolean,
|
||||||
generateSourceMaps?: boolean,
|
generateSourceMaps?: boolean,
|
||||||
}): Promise<Array<Module>> {
|
}): Promise<Array<Module>> {
|
||||||
return this.getTransformOptions(
|
return this.getTransformOptions(entryFile, {
|
||||||
entryFile,
|
enableBabelRCLookup: this._opts.enableBabelRCLookup,
|
||||||
{
|
dev,
|
||||||
enableBabelRCLookup: this._opts.enableBabelRCLookup,
|
generateSourceMaps,
|
||||||
dev,
|
hot,
|
||||||
generateSourceMaps,
|
minify,
|
||||||
hot,
|
platform,
|
||||||
minify,
|
projectRoots: this._projectRoots,
|
||||||
platform,
|
}).then(bundlingOptions =>
|
||||||
projectRoots: this._projectRoots,
|
|
||||||
},
|
|
||||||
).then(bundlingOptions =>
|
|
||||||
this._resolverPromise.then(resolver =>
|
this._resolverPromise.then(resolver =>
|
||||||
resolver.getShallowDependencies(entryFile, bundlingOptions.transformer),
|
resolver.getShallowDependencies(entryFile, bundlingOptions.transformer),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getModuleForPath(entryFile: string): Promise<Module> {
|
getModuleForPath(entryFile: string): Promise<Module> {
|
||||||
return this._resolverPromise.then(resolver => resolver.getModuleForPath(entryFile));
|
return this._resolverPromise.then(resolver =>
|
||||||
|
resolver.getModuleForPath(entryFile),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDependencies({
|
async getDependencies({
|
||||||
|
@ -612,42 +645,47 @@ class Bundler {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
getOrderedDependencyPaths({entryFile, dev, platform, minify, generateSourceMaps}: {
|
getOrderedDependencyPaths({
|
||||||
|
entryFile,
|
||||||
|
dev,
|
||||||
|
platform,
|
||||||
|
minify,
|
||||||
|
generateSourceMaps,
|
||||||
|
}: {
|
||||||
+entryFile: string,
|
+entryFile: string,
|
||||||
+dev: boolean,
|
+dev: boolean,
|
||||||
+platform: string,
|
+platform: string,
|
||||||
+minify: boolean,
|
+minify: boolean,
|
||||||
+generateSourceMaps: boolean,
|
+generateSourceMaps: boolean,
|
||||||
}) {
|
}) {
|
||||||
return this.getDependencies({entryFile, dev, platform, minify, generateSourceMaps}).then(
|
return this.getDependencies({
|
||||||
({dependencies}) => {
|
entryFile,
|
||||||
const ret = [];
|
dev,
|
||||||
const promises = [];
|
platform,
|
||||||
const placeHolder = {};
|
minify,
|
||||||
dependencies.forEach(dep => {
|
generateSourceMaps,
|
||||||
if (dep.isAsset()) {
|
}).then(({dependencies}) => {
|
||||||
const localPath = toLocalPath(
|
const ret = [];
|
||||||
this._projectRoots,
|
const promises = [];
|
||||||
dep.path
|
const placeHolder = {};
|
||||||
);
|
dependencies.forEach(dep => {
|
||||||
promises.push(
|
if (dep.isAsset()) {
|
||||||
this._assetServer.getAssetData(localPath, platform)
|
const localPath = toLocalPath(this._projectRoots, dep.path);
|
||||||
);
|
promises.push(this._assetServer.getAssetData(localPath, platform));
|
||||||
ret.push(placeHolder);
|
ret.push(placeHolder);
|
||||||
} else {
|
} else {
|
||||||
ret.push(dep.path);
|
ret.push(dep.path);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(promises).then(assetsData => {
|
return Promise.all(promises).then(assetsData => {
|
||||||
assetsData.forEach(({files}) => {
|
assetsData.forEach(({files}) => {
|
||||||
const index = ret.indexOf(placeHolder);
|
const index = ret.indexOf(placeHolder);
|
||||||
ret.splice(index, 1, ...files);
|
ret.splice(index, 1, ...files);
|
||||||
});
|
|
||||||
return ret;
|
|
||||||
});
|
});
|
||||||
}
|
return ret;
|
||||||
);
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_toModuleTransport({
|
_toModuleTransport({
|
||||||
|
@ -673,7 +711,12 @@ class Bundler {
|
||||||
|
|
||||||
if (module.isAsset()) {
|
if (module.isAsset()) {
|
||||||
moduleTransport = this._generateAssetModule(
|
moduleTransport = this._generateAssetModule(
|
||||||
bundle, module, moduleId, assetPlugins, transformOptions.platform);
|
bundle,
|
||||||
|
module,
|
||||||
|
moduleId,
|
||||||
|
assetPlugins,
|
||||||
|
transformOptions.platform,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moduleTransport) {
|
if (moduleTransport) {
|
||||||
|
@ -683,15 +726,14 @@ class Bundler {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
module.getName(),
|
module.getName(),
|
||||||
module.read(transformOptions),
|
module.read(transformOptions),
|
||||||
]).then((
|
]).then(([name, {code, dependencies, dependencyOffsets, map, source}]) => {
|
||||||
[name, {code, dependencies, dependencyOffsets, map, source}]
|
|
||||||
) => {
|
|
||||||
const {preloadedModules} = options;
|
const {preloadedModules} = options;
|
||||||
const isPolyfill = module.isPolyfill();
|
const isPolyfill = module.isPolyfill();
|
||||||
const preloaded =
|
const preloaded =
|
||||||
module.path === entryFilePath ||
|
module.path === entryFilePath ||
|
||||||
isPolyfill ||
|
isPolyfill ||
|
||||||
preloadedModules && hasOwnProperty.call(preloadedModules, module.path);
|
(preloadedModules &&
|
||||||
|
hasOwnProperty.call(preloadedModules, module.path));
|
||||||
|
|
||||||
return new ModuleTransport({
|
return new ModuleTransport({
|
||||||
name,
|
name,
|
||||||
|
@ -721,35 +763,45 @@ class Bundler {
|
||||||
|
|
||||||
const isImage = isAssetTypeAnImage(extname(module.path).slice(1));
|
const isImage = isAssetTypeAnImage(extname(module.path).slice(1));
|
||||||
|
|
||||||
return this._assetServer.getAssetData(localPath, platform).then(assetData => {
|
return this._assetServer
|
||||||
return Promise.all([isImage ? sizeOf(assetData.files[0]) : null, assetData]);
|
.getAssetData(localPath, platform)
|
||||||
}).then(res => {
|
.then(assetData => {
|
||||||
const dimensions = res[0];
|
return Promise.all([
|
||||||
const assetData = res[1];
|
isImage ? sizeOf(assetData.files[0]) : null,
|
||||||
const scale = assetData.scales[0];
|
assetData,
|
||||||
const asset = {
|
]);
|
||||||
__packager_asset: true,
|
})
|
||||||
fileSystemLocation: pathDirname(module.path),
|
.then(res => {
|
||||||
httpServerLocation: assetUrlPath,
|
const dimensions = res[0];
|
||||||
width: dimensions ? dimensions.width / scale : undefined,
|
const assetData = res[1];
|
||||||
height: dimensions ? dimensions.height / scale : undefined,
|
const scale = assetData.scales[0];
|
||||||
scales: assetData.scales,
|
const asset = {
|
||||||
files: assetData.files,
|
__packager_asset: true,
|
||||||
hash: assetData.hash,
|
fileSystemLocation: pathDirname(module.path),
|
||||||
name: assetData.name,
|
httpServerLocation: assetUrlPath,
|
||||||
type: assetData.type,
|
width: dimensions ? dimensions.width / scale : undefined,
|
||||||
};
|
height: dimensions ? dimensions.height / scale : undefined,
|
||||||
|
scales: assetData.scales,
|
||||||
|
files: assetData.files,
|
||||||
|
hash: assetData.hash,
|
||||||
|
name: assetData.name,
|
||||||
|
type: assetData.type,
|
||||||
|
};
|
||||||
|
|
||||||
return this._applyAssetPlugins(assetPlugins, asset);
|
return this._applyAssetPlugins(assetPlugins, asset);
|
||||||
}).then(asset => {
|
})
|
||||||
const {code, dependencies, dependencyOffsets} =
|
.then(asset => {
|
||||||
generateAssetTransformResult(this._opts.assetRegistryPath, asset);
|
const {
|
||||||
return {
|
code,
|
||||||
asset,
|
dependencies,
|
||||||
code,
|
dependencyOffsets,
|
||||||
meta: {dependencies, dependencyOffsets, preloaded: null},
|
} = generateAssetTransformResult(this._opts.assetRegistryPath, asset);
|
||||||
};
|
return {
|
||||||
});
|
asset,
|
||||||
|
code,
|
||||||
|
meta: {dependencies, dependencyOffsets, preloaded: null},
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyAssetPlugins(
|
_applyAssetPlugins(
|
||||||
|
@ -769,7 +821,7 @@ class Bundler {
|
||||||
// applying the remaining plugins
|
// applying the remaining plugins
|
||||||
if (typeof result.then === 'function') {
|
if (typeof result.then === 'function') {
|
||||||
return result.then(resultAsset =>
|
return result.then(resultAsset =>
|
||||||
this._applyAssetPlugins(remainingAssetPlugins, resultAsset)
|
this._applyAssetPlugins(remainingAssetPlugins, resultAsset),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return this._applyAssetPlugins(remainingAssetPlugins, result);
|
return this._applyAssetPlugins(remainingAssetPlugins, result);
|
||||||
|
@ -811,14 +863,19 @@ class Bundler {
|
||||||
platform: ?string,
|
platform: ?string,
|
||||||
projectRoots: $ReadOnlyArray<string>,
|
projectRoots: $ReadOnlyArray<string>,
|
||||||
|},
|
|},
|
||||||
): Promise<BundlingOptions> {
|
): Promise<BundlingOptions> {
|
||||||
const getDependencies = (entryFile: string) =>
|
const getDependencies = (entryFile: string) =>
|
||||||
this.getDependencies({...options, entryFile})
|
this.getDependencies({...options, entryFile}).then(r =>
|
||||||
.then(r => r.dependencies.map(d => d.path));
|
r.dependencies.map(d => d.path),
|
||||||
|
);
|
||||||
|
|
||||||
const {dev, hot, platform} = options;
|
const {dev, hot, platform} = options;
|
||||||
const extraOptions: ExtraTransformOptions = this._getTransformOptions
|
const extraOptions: ExtraTransformOptions = this._getTransformOptions
|
||||||
? await this._getTransformOptions(mainModuleName, {dev, hot, platform}, getDependencies)
|
? await this._getTransformOptions(
|
||||||
|
mainModuleName,
|
||||||
|
{dev, hot, platform},
|
||||||
|
getDependencies,
|
||||||
|
)
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
const {transform = {}} = extraOptions;
|
const {transform = {}} = extraOptions;
|
||||||
|
@ -846,7 +903,6 @@ class Bundler {
|
||||||
getResolver(): Promise<Resolver> {
|
getResolver(): Promise<Resolver> {
|
||||||
return this._resolverPromise;
|
return this._resolverPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function verifyRootExists(root) {
|
function verifyRootExists(root) {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @flow
|
* @flow
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @flow
|
* @flow
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
@ -77,13 +78,16 @@ class Generator {
|
||||||
*/
|
*/
|
||||||
addSimpleMapping(generatedLine: number, generatedColumn: number): void {
|
addSimpleMapping(generatedLine: number, generatedColumn: number): void {
|
||||||
const last = this.last;
|
const last = this.last;
|
||||||
if (this.source === -1 ||
|
if (
|
||||||
generatedLine === last.generatedLine &&
|
this.source === -1 ||
|
||||||
generatedColumn < last.generatedColumn ||
|
(generatedLine === last.generatedLine &&
|
||||||
generatedLine < last.generatedLine) {
|
generatedColumn < last.generatedColumn) ||
|
||||||
const msg = this.source === -1
|
generatedLine < last.generatedLine
|
||||||
? 'Cannot add mapping before starting a file with `addFile()`'
|
) {
|
||||||
: 'Mapping is for a position preceding an earlier mapping';
|
const msg =
|
||||||
|
this.source === -1
|
||||||
|
? 'Cannot add mapping before starting a file with `addFile()`'
|
||||||
|
: 'Mapping is for a position preceding an earlier mapping';
|
||||||
throw new Error(msg);
|
throw new Error(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +134,11 @@ class Generator {
|
||||||
name: string,
|
name: string,
|
||||||
): void {
|
): void {
|
||||||
this.addSourceMapping(
|
this.addSourceMapping(
|
||||||
generatedLine, generatedColumn, sourceLine, sourceColumn);
|
generatedLine,
|
||||||
|
generatedColumn,
|
||||||
|
sourceLine,
|
||||||
|
sourceColumn,
|
||||||
|
);
|
||||||
|
|
||||||
const last = this.last;
|
const last = this.last;
|
||||||
const nameIndex = this.names.indexFor(name);
|
const nameIndex = this.names.indexFor(name);
|
||||||
|
@ -158,14 +166,16 @@ class Generator {
|
||||||
* This is ~2.5x faster than calling `JSON.stringify(generator.toMap())`
|
* This is ~2.5x faster than calling `JSON.stringify(generator.toMap())`
|
||||||
*/
|
*/
|
||||||
toString(file?: string): string {
|
toString(file?: string): string {
|
||||||
return ('{' +
|
return (
|
||||||
|
'{' +
|
||||||
'"version":3,' +
|
'"version":3,' +
|
||||||
(file ? `"file":${JSON.stringify(file)},` : '') +
|
(file ? `"file":${JSON.stringify(file)},` : '') +
|
||||||
`"sources":${JSON.stringify(this.sources)},` +
|
`"sources":${JSON.stringify(this.sources)},` +
|
||||||
`"sourcesContent":${JSON.stringify(this.sourcesContent)},` +
|
`"sourcesContent":${JSON.stringify(this.sourcesContent)},` +
|
||||||
`"names":${JSON.stringify(this.names.items())},` +
|
`"names":${JSON.stringify(this.names.items())},` +
|
||||||
`"mappings":"${this.builder.toString()}"` +
|
`"mappings":"${this.builder.toString()}"` +
|
||||||
'}');
|
'}'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,10 @@
|
||||||
* This source code is licensed under the BSD-style license found in the
|
* This source code is licensed under the BSD-style license found in the
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const B64Builder = require('../B64Builder');
|
const B64Builder = require('../B64Builder');
|
||||||
|
|
|
@ -5,7 +5,10 @@
|
||||||
* This source code is licensed under the BSD-style license found in the
|
* This source code is licensed under the BSD-style license found in the
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Generator = require('../Generator');
|
const Generator = require('../Generator');
|
||||||
|
@ -26,11 +29,12 @@ it('adds file name and source code when starting a file', () => {
|
||||||
generator.startFile(file1, source1);
|
generator.startFile(file1, source1);
|
||||||
generator.startFile(file2, source2);
|
generator.startFile(file2, source2);
|
||||||
|
|
||||||
expect(generator.toMap())
|
expect(generator.toMap()).toEqual(
|
||||||
.toEqual(objectContaining({
|
objectContaining({
|
||||||
sources: [file1, file2],
|
sources: [file1, file2],
|
||||||
sourcesContent: [source1, source2],
|
sourcesContent: [source1, source2],
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws when adding a mapping without starting a file', () => {
|
it('throws when adding a mapping without starting a file', () => {
|
||||||
|
@ -46,29 +50,32 @@ it('throws when adding a mapping after ending a file', () => {
|
||||||
it('can add a mapping for generated code without corresponding original source', () => {
|
it('can add a mapping for generated code without corresponding original source', () => {
|
||||||
generator.startFile('apples', 'pears');
|
generator.startFile('apples', 'pears');
|
||||||
generator.addSimpleMapping(12, 87);
|
generator.addSimpleMapping(12, 87);
|
||||||
expect(generator.toMap())
|
expect(generator.toMap()).toEqual(
|
||||||
.toEqual(objectContaining({
|
objectContaining({
|
||||||
mappings: ';;;;;;;;;;;uF',
|
mappings: ';;;;;;;;;;;uF',
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can add a mapping with corresponding location in the original source', () => {
|
it('can add a mapping with corresponding location in the original source', () => {
|
||||||
generator.startFile('apples', 'pears');
|
generator.startFile('apples', 'pears');
|
||||||
generator.addSourceMapping(2, 3, 456, 7);
|
generator.addSourceMapping(2, 3, 456, 7);
|
||||||
expect(generator.toMap())
|
expect(generator.toMap()).toEqual(
|
||||||
.toEqual(objectContaining({
|
objectContaining({
|
||||||
mappings: ';GAucO',
|
mappings: ';GAucO',
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can add a mapping with source location and symbol name', () => {
|
it('can add a mapping with source location and symbol name', () => {
|
||||||
generator.startFile('apples', 'pears');
|
generator.startFile('apples', 'pears');
|
||||||
generator.addNamedSourceMapping(9, 876, 54, 3, 'arbitrary');
|
generator.addNamedSourceMapping(9, 876, 54, 3, 'arbitrary');
|
||||||
expect(generator.toMap())
|
expect(generator.toMap()).toEqual(
|
||||||
.toEqual(objectContaining({
|
objectContaining({
|
||||||
mappings: ';;;;;;;;42BAqDGA',
|
mappings: ';;;;;;;;42BAqDGA',
|
||||||
names: ['arbitrary'],
|
names: ['arbitrary'],
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('full map generation', () => {
|
describe('full map generation', () => {
|
||||||
|
@ -94,10 +101,11 @@ describe('full map generation', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can add a `file` property to the map', () => {
|
it('can add a `file` property to the map', () => {
|
||||||
expect(generator.toMap('arbitrary'))
|
expect(generator.toMap('arbitrary')).toEqual(
|
||||||
.toEqual(objectContaining({
|
objectContaining({
|
||||||
file: 'arbitrary',
|
file: 'arbitrary',
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('supports direct JSON serialization', () => {
|
it('supports direct JSON serialization', () => {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2017-present, Facebook, Inc.
|
* Copyright (c) 2017-present, Facebook, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This source code is licensed under the BSD-style license found in the
|
* This source code is licensed under the BSD-style license found in the
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Generator = require('../Generator');
|
const Generator = require('../Generator');
|
||||||
|
@ -13,23 +16,29 @@ const {compactMapping, fromRawMappings} = require('..');
|
||||||
|
|
||||||
describe('flattening mappings / compacting', () => {
|
describe('flattening mappings / compacting', () => {
|
||||||
it('flattens simple mappings', () => {
|
it('flattens simple mappings', () => {
|
||||||
expect(compactMapping({generated: {line: 12, column: 34}}))
|
expect(compactMapping({generated: {line: 12, column: 34}})).toEqual([
|
||||||
.toEqual([12, 34]);
|
12,
|
||||||
|
34,
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('flattens mappings with a source location', () => {
|
it('flattens mappings with a source location', () => {
|
||||||
expect(compactMapping({
|
expect(
|
||||||
generated: {column: 34, line: 12},
|
compactMapping({
|
||||||
original: {column: 78, line: 56},
|
generated: {column: 34, line: 12},
|
||||||
})).toEqual([12, 34, 56, 78]);
|
original: {column: 78, line: 56},
|
||||||
|
}),
|
||||||
|
).toEqual([12, 34, 56, 78]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('flattens mappings with a source location and a symbol name', () => {
|
it('flattens mappings with a source location and a symbol name', () => {
|
||||||
expect(compactMapping({
|
expect(
|
||||||
generated: {column: 34, line: 12},
|
compactMapping({
|
||||||
name: 'arbitrary',
|
generated: {column: 34, line: 12},
|
||||||
original: {column: 78, line: 56},
|
name: 'arbitrary',
|
||||||
})).toEqual([12, 34, 56, 78, 'arbitrary']);
|
original: {column: 78, line: 56},
|
||||||
|
}),
|
||||||
|
).toEqual([12, 34, 56, 78, 'arbitrary']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -39,44 +48,45 @@ describe('build map from raw mappings', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns a working source map containing all mappings', () => {
|
it('returns a working source map containing all mappings', () => {
|
||||||
const input = [{
|
const input = [
|
||||||
code: lines(11),
|
{
|
||||||
map: [
|
code: lines(11),
|
||||||
[1, 2],
|
map: [
|
||||||
[3, 4, 5, 6, 'apples'],
|
[1, 2],
|
||||||
[7, 8, 9, 10],
|
[3, 4, 5, 6, 'apples'],
|
||||||
[11, 12, 13, 14, 'pears'],
|
[7, 8, 9, 10],
|
||||||
],
|
[11, 12, 13, 14, 'pears'],
|
||||||
sourceCode: 'code1',
|
],
|
||||||
sourcePath: 'path1',
|
sourceCode: 'code1',
|
||||||
}, {
|
sourcePath: 'path1',
|
||||||
code: lines(3),
|
},
|
||||||
map: [
|
{
|
||||||
[1, 2],
|
code: lines(3),
|
||||||
[3, 4, 15, 16, 'bananas'],
|
map: [[1, 2], [3, 4, 15, 16, 'bananas']],
|
||||||
],
|
sourceCode: 'code2',
|
||||||
sourceCode: 'code2',
|
sourcePath: 'path2',
|
||||||
sourcePath: 'path2',
|
},
|
||||||
}, {
|
{
|
||||||
code: lines(23),
|
code: lines(23),
|
||||||
map: [
|
map: [
|
||||||
[11, 12],
|
[11, 12],
|
||||||
[13, 14, 15, 16, 'bananas'],
|
[13, 14, 15, 16, 'bananas'],
|
||||||
[17, 18, 19, 110],
|
[17, 18, 19, 110],
|
||||||
[21, 112, 113, 114, 'pears'],
|
[21, 112, 113, 114, 'pears'],
|
||||||
],
|
],
|
||||||
sourceCode: 'code3',
|
sourceCode: 'code3',
|
||||||
sourcePath: 'path3',
|
sourcePath: 'path3',
|
||||||
}];
|
},
|
||||||
|
];
|
||||||
|
|
||||||
expect(fromRawMappings(input).toMap())
|
expect(fromRawMappings(input).toMap()).toEqual({
|
||||||
.toEqual({
|
mappings:
|
||||||
mappings: 'E;;IAIMA;;;;QAII;;;;YAIIC;E;;ICEEC;;;;;;;;;;;Y;;cCAAA;;;;kBAI8F;;;;gHA8FID',
|
'E;;IAIMA;;;;QAII;;;;YAIIC;E;;ICEEC;;;;;;;;;;;Y;;cCAAA;;;;kBAI8F;;;;gHA8FID',
|
||||||
names: ['apples', 'pears', 'bananas'],
|
names: ['apples', 'pears', 'bananas'],
|
||||||
sources: ['path1', 'path2', 'path3'],
|
sources: ['path1', 'path2', 'path3'],
|
||||||
sourcesContent: ['code1', 'code2', 'code3'],
|
sourcesContent: ['code1', 'code2', 'code3'],
|
||||||
version: 3,
|
version: 3,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @flow
|
* @flow
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,14 +54,70 @@
|
||||||
|
|
||||||
// A map of values to characters for the b64 encoding
|
// A map of values to characters for the b64 encoding
|
||||||
const CHAR_MAP = [
|
const CHAR_MAP = [
|
||||||
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
|
0x41,
|
||||||
0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
|
0x42,
|
||||||
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
0x43,
|
||||||
0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
|
0x44,
|
||||||
0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
|
0x45,
|
||||||
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
|
0x46,
|
||||||
0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33,
|
0x47,
|
||||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f,
|
0x48,
|
||||||
|
0x49,
|
||||||
|
0x4a,
|
||||||
|
0x4b,
|
||||||
|
0x4c,
|
||||||
|
0x4d,
|
||||||
|
0x4e,
|
||||||
|
0x4f,
|
||||||
|
0x50,
|
||||||
|
0x51,
|
||||||
|
0x52,
|
||||||
|
0x53,
|
||||||
|
0x54,
|
||||||
|
0x55,
|
||||||
|
0x56,
|
||||||
|
0x57,
|
||||||
|
0x58,
|
||||||
|
0x59,
|
||||||
|
0x5a,
|
||||||
|
0x61,
|
||||||
|
0x62,
|
||||||
|
0x63,
|
||||||
|
0x64,
|
||||||
|
0x65,
|
||||||
|
0x66,
|
||||||
|
0x67,
|
||||||
|
0x68,
|
||||||
|
0x69,
|
||||||
|
0x6a,
|
||||||
|
0x6b,
|
||||||
|
0x6c,
|
||||||
|
0x6d,
|
||||||
|
0x6e,
|
||||||
|
0x6f,
|
||||||
|
0x70,
|
||||||
|
0x71,
|
||||||
|
0x72,
|
||||||
|
0x73,
|
||||||
|
0x74,
|
||||||
|
0x75,
|
||||||
|
0x76,
|
||||||
|
0x77,
|
||||||
|
0x78,
|
||||||
|
0x79,
|
||||||
|
0x7a,
|
||||||
|
0x30,
|
||||||
|
0x31,
|
||||||
|
0x32,
|
||||||
|
0x33,
|
||||||
|
0x34,
|
||||||
|
0x35,
|
||||||
|
0x36,
|
||||||
|
0x37,
|
||||||
|
0x38,
|
||||||
|
0x39,
|
||||||
|
0x2b,
|
||||||
|
0x2f,
|
||||||
];
|
];
|
||||||
|
|
||||||
// A single base 64 digit can contain 6 bits of data. For the base 64 variable
|
// A single base 64 digit can contain 6 bits of data. For the base 64 variable
|
||||||
|
@ -93,9 +150,7 @@ const VLQ_CONTINUATION_BIT = VLQ_BASE;
|
||||||
* 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
|
* 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
|
||||||
*/
|
*/
|
||||||
function toVLQSigned(value) {
|
function toVLQSigned(value) {
|
||||||
return value < 0
|
return value < 0 ? (-value << 1) + 1 : (value << 1) + 0;
|
||||||
? ((-value) << 1) + 1
|
|
||||||
: (value << 1) + 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @flow
|
* @flow
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
@ -18,10 +19,12 @@ import type {RawMapping as BabelRawMapping} from 'babel-generator';
|
||||||
|
|
||||||
type GeneratedCodeMapping = [number, number];
|
type GeneratedCodeMapping = [number, number];
|
||||||
type SourceMapping = [number, number, number, number];
|
type SourceMapping = [number, number, number, number];
|
||||||
type SourceMappingWithName = [number, number, number, number, string];
|
type SourceMappingWithName = [number, number, number, number, string];
|
||||||
|
|
||||||
export type RawMapping =
|
export type RawMapping =
|
||||||
SourceMappingWithName | SourceMapping | GeneratedCodeMapping;
|
| SourceMappingWithName
|
||||||
|
| SourceMapping
|
||||||
|
| GeneratedCodeMapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a source map from modules with "raw mappings", i.e. an array of
|
* Creates a source map from modules with "raw mappings", i.e. an array of
|
||||||
|
@ -40,7 +43,7 @@ function fromRawMappings(modules: Array<ModuleTransport>): Generator {
|
||||||
addMappingsForFile(generator, map, module, carryOver);
|
addMappingsForFile(generator, map, module, carryOver);
|
||||||
} else if (map != null) {
|
} else if (map != null) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unexpected module with full source map found: ${module.sourcePath}`
|
`Unexpected module with full source map found: ${module.sourcePath}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +77,6 @@ function addMappingsForFile(generator, mappings, module, carryOver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
generator.endFile();
|
generator.endFile();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addMapping(generator, mapping, carryOver, columnOffset) {
|
function addMapping(generator, mapping, carryOver, columnOffset) {
|
||||||
|
@ -89,8 +91,15 @@ function addMapping(generator, mapping, carryOver, columnOffset) {
|
||||||
generator.addSourceMapping(line, column, mapping[2], mapping[3]);
|
generator.addSourceMapping(line, column, mapping[2], mapping[3]);
|
||||||
} else if (n === 5) {
|
} else if (n === 5) {
|
||||||
generator.addNamedSourceMapping(
|
generator.addNamedSourceMapping(
|
||||||
|
line,
|
||||||
|
column,
|
||||||
// $FlowIssue #15579526
|
// $FlowIssue #15579526
|
||||||
line, column, mapping[2], mapping[3], mapping[4]);
|
mapping[2],
|
||||||
|
// $FlowIssue #15579526
|
||||||
|
mapping[3],
|
||||||
|
// $FlowIssue #15579526
|
||||||
|
mapping[4],
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Invalid mapping: [${mapping.join(', ')}]`);
|
throw new Error(`Invalid mapping: [${mapping.join(', ')}]`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @flow
|
* @flow
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
@ -23,27 +24,41 @@ type SubTree<T: ModuleTransportLike> = (
|
||||||
moduleTransportsByPath: Map<string, T>,
|
moduleTransportsByPath: Map<string, T>,
|
||||||
) => Generator<number, void, void>;
|
) => Generator<number, void, void>;
|
||||||
|
|
||||||
const assetPropertyBlacklist = new Set([
|
const assetPropertyBlacklist = new Set(['files', 'fileSystemLocation', 'path']);
|
||||||
'files',
|
|
||||||
'fileSystemLocation',
|
|
||||||
'path',
|
|
||||||
]);
|
|
||||||
|
|
||||||
function generateAssetCodeFileAst(
|
function generateAssetCodeFileAst(
|
||||||
assetRegistryPath: string,
|
assetRegistryPath: string,
|
||||||
assetDescriptor: AssetDescriptor,
|
assetDescriptor: AssetDescriptor,
|
||||||
): Object {
|
): Object {
|
||||||
const properDescriptor = filterObject(assetDescriptor, assetPropertyBlacklist);
|
const properDescriptor = filterObject(
|
||||||
const descriptorAst = babylon.parseExpression(JSON.stringify(properDescriptor));
|
assetDescriptor,
|
||||||
|
assetPropertyBlacklist,
|
||||||
|
);
|
||||||
|
const descriptorAst = babylon.parseExpression(
|
||||||
|
JSON.stringify(properDescriptor),
|
||||||
|
);
|
||||||
const t = babel.types;
|
const t = babel.types;
|
||||||
const moduleExports = t.memberExpression(t.identifier('module'), t.identifier('exports'));
|
const moduleExports = t.memberExpression(
|
||||||
const requireCall =
|
t.identifier('module'),
|
||||||
t.callExpression(t.identifier('require'), [t.stringLiteral(assetRegistryPath)]);
|
t.identifier('exports'),
|
||||||
const registerAssetFunction = t.memberExpression(requireCall, t.identifier('registerAsset'));
|
);
|
||||||
const registerAssetCall = t.callExpression(registerAssetFunction, [descriptorAst]);
|
const requireCall = t.callExpression(t.identifier('require'), [
|
||||||
return t.file(t.program([
|
t.stringLiteral(assetRegistryPath),
|
||||||
t.expressionStatement(t.assignmentExpression('=', moduleExports, registerAssetCall)),
|
]);
|
||||||
]));
|
const registerAssetFunction = t.memberExpression(
|
||||||
|
requireCall,
|
||||||
|
t.identifier('registerAsset'),
|
||||||
|
);
|
||||||
|
const registerAssetCall = t.callExpression(registerAssetFunction, [
|
||||||
|
descriptorAst,
|
||||||
|
]);
|
||||||
|
return t.file(
|
||||||
|
t.program([
|
||||||
|
t.expressionStatement(
|
||||||
|
t.assignmentExpression('=', moduleExports, registerAssetCall),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateAssetTransformResult(
|
function generateAssetTransformResult(
|
||||||
|
@ -66,9 +81,11 @@ function generateAssetTransformResult(
|
||||||
// Test extension against all types supported by image-size module.
|
// Test extension against all types supported by image-size module.
|
||||||
// If it's not one of these, we won't treat it as an image.
|
// If it's not one of these, we won't treat it as an image.
|
||||||
function isAssetTypeAnImage(type: string): boolean {
|
function isAssetTypeAnImage(type: string): boolean {
|
||||||
return [
|
return (
|
||||||
'png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp', 'psd', 'svg', 'tiff',
|
['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp', 'psd', 'svg', 'tiff'].indexOf(
|
||||||
].indexOf(type) !== -1;
|
type,
|
||||||
|
) !== -1
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterObject(object, blacklist) {
|
function filterObject(object, blacklist) {
|
||||||
|
@ -95,18 +112,17 @@ function createRamBundleGroups<T: ModuleTransportLike>(
|
||||||
|
|
||||||
// build a map of group root IDs to an array of module IDs in the group
|
// build a map of group root IDs to an array of module IDs in the group
|
||||||
const result: Map<number, Set<number>> = new Map(
|
const result: Map<number, Set<number>> = new Map(
|
||||||
ramGroups
|
ramGroups.map(modulePath => {
|
||||||
.map(modulePath => {
|
const root = byPath.get(modulePath);
|
||||||
const root = byPath.get(modulePath);
|
if (root == null) {
|
||||||
if (root == null) {
|
throw Error(`Group root ${modulePath} is not part of the bundle`);
|
||||||
throw Error(`Group root ${modulePath} is not part of the bundle`);
|
}
|
||||||
}
|
return [
|
||||||
return [
|
root.id,
|
||||||
root.id,
|
// `subtree` yields the IDs of all transitive dependencies of a module
|
||||||
// `subtree` yields the IDs of all transitive dependencies of a module
|
new Set(subtree(root, byPath)),
|
||||||
new Set(subtree(root, byPath)),
|
];
|
||||||
];
|
}),
|
||||||
})
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (ramGroups.length > 1) {
|
if (ramGroups.length > 1) {
|
||||||
|
@ -124,9 +140,10 @@ function createRamBundleGroups<T: ModuleTransportLike>(
|
||||||
const parentNames = parents.map(byId.get, byId);
|
const parentNames = parents.map(byId.get, byId);
|
||||||
const lastName = parentNames.pop();
|
const lastName = parentNames.pop();
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Module ${byId.get(moduleId) || moduleId} belongs to groups ${
|
`Module ${byId.get(moduleId) ||
|
||||||
parentNames.join(', ')}, and ${String(lastName)
|
moduleId} belongs to groups ${parentNames.join(', ')}, and ${String(
|
||||||
}. Ensure that each module is only part of one group.`
|
lastName,
|
||||||
|
)}. Ensure that each module is only part of one group.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,7 +151,7 @@ function createRamBundleGroups<T: ModuleTransportLike>(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function * filter(iterator, predicate) {
|
function* filter(iterator, predicate) {
|
||||||
for (const value of iterator) {
|
for (const value of iterator) {
|
||||||
if (predicate(value)) {
|
if (predicate(value)) {
|
||||||
yield value;
|
yield value;
|
||||||
|
|
Loading…
Reference in New Issue