mirror of https://github.com/status-im/metro.git
Allow to pass custom transformer parameters via the request url
Reviewed By: davidaurelio Differential Revision: D6869137 fbshipit-source-id: a985b2df7e4fca308e62adaededc2ad0038d5373
This commit is contained in:
parent
cd23c579b5
commit
79fd0b341e
|
@ -160,6 +160,7 @@ class DeltaCalculator extends EventEmitter {
|
|||
|
||||
const transformOptionsForBlacklist = {
|
||||
assetDataPlugins: this._options.assetPlugins,
|
||||
customTransformOptions: this._options.customTransformOptions,
|
||||
enableBabelRCLookup,
|
||||
dev: this._options.dev,
|
||||
hot: this._options.hot,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
'use strict';
|
||||
|
||||
import type {Options as BundleOptions} from '../DeltaBundler';
|
||||
import type {CustomTransformOptions} from '../JSTransformer/worker';
|
||||
|
||||
/**
|
||||
* Module to easily create the needed configuration parameters needed for the
|
||||
|
@ -21,6 +22,7 @@ import type {Options as BundleOptions} from '../DeltaBundler';
|
|||
module.exports = function getBundlingOptionsForHmr(
|
||||
entryFile: string,
|
||||
platform: string,
|
||||
customTransformOptions: CustomTransformOptions,
|
||||
): BundleOptions {
|
||||
// These are the really meaningful bundling options. The others below are
|
||||
// not relevant for HMR.
|
||||
|
@ -36,6 +38,7 @@ module.exports = function getBundlingOptionsForHmr(
|
|||
...mainOptions,
|
||||
assetPlugins: [],
|
||||
bundleType: 'hmr',
|
||||
customTransformOptions,
|
||||
dev: true,
|
||||
entryModuleOnly: false,
|
||||
excludeSource: false,
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
const addParamsToDefineCall = require('../lib/addParamsToDefineCall');
|
||||
const formatBundlingError = require('../lib/formatBundlingError');
|
||||
const getBundlingOptionsForHmr = require('./getBundlingOptionsForHmr');
|
||||
const nullthrows = require('fbjs/lib/nullthrows');
|
||||
const parseCustomTransformOptions = require('../lib/parseCustomTransformOptions');
|
||||
const querystring = require('querystring');
|
||||
const url = require('url');
|
||||
|
||||
|
@ -53,10 +55,10 @@ class HmrServer<TClient: Client> {
|
|||
clientUrl: string,
|
||||
sendFn: (data: string) => mixed,
|
||||
): Promise<Client> {
|
||||
const {bundleEntry, platform} = querystring.parse(
|
||||
/* $FlowFixMe: url might be null */
|
||||
url.parse(clientUrl).query,
|
||||
);
|
||||
const urlObj = nullthrows(url.parse(clientUrl, true));
|
||||
|
||||
const {bundleEntry, platform} = nullthrows(urlObj.query);
|
||||
const customTransformOptions = parseCustomTransformOptions(urlObj);
|
||||
|
||||
// Create a new DeltaTransformer for each client. Once the clients are
|
||||
// modified to support Delta Bundles, they'll be able to pass the
|
||||
|
@ -64,7 +66,7 @@ class HmrServer<TClient: Client> {
|
|||
// the same DeltaTransformer between the WS connection and the HTTP one.
|
||||
const deltaBundler = this._packagerServer.getDeltaBundler();
|
||||
const {deltaTransformer} = await deltaBundler.getDeltaTransformer(
|
||||
getBundlingOptionsForHmr(bundleEntry, platform),
|
||||
getBundlingOptionsForHmr(bundleEntry, platform, customTransformOptions),
|
||||
);
|
||||
|
||||
// Trigger an initial build to start up the DeltaTransformer.
|
||||
|
|
|
@ -62,8 +62,11 @@ export type Transformer<ExtraOptions: {} = {}> = {
|
|||
getCacheKey: () => string,
|
||||
};
|
||||
|
||||
export type CustomTransformOptions = {[string]: mixed, __proto__: null};
|
||||
|
||||
export type TransformOptionsStrict = {|
|
||||
+assetDataPlugins: $ReadOnlyArray<string>,
|
||||
+customTransformOptions?: CustomTransformOptions,
|
||||
+enableBabelRCLookup: boolean,
|
||||
+dev: boolean,
|
||||
+hot: boolean,
|
||||
|
@ -75,6 +78,7 @@ export type TransformOptionsStrict = {|
|
|||
|
||||
export type TransformOptions = {
|
||||
+assetDataPlugins: $ReadOnlyArray<string>,
|
||||
+customTransformOptions?: CustomTransformOptions,
|
||||
+enableBabelRCLookup?: boolean,
|
||||
+dev?: boolean,
|
||||
+hot?: boolean,
|
||||
|
|
|
@ -183,6 +183,7 @@ describe('processRequest', () => {
|
|||
{
|
||||
assetPlugins: [],
|
||||
bundleType: 'bundle',
|
||||
customTransformOptions: {},
|
||||
deltaBundleId: expect.any(String),
|
||||
dev: true,
|
||||
entryFile: 'index.ios.js',
|
||||
|
@ -214,6 +215,7 @@ describe('processRequest', () => {
|
|||
{
|
||||
assetPlugins: [],
|
||||
bundleType: 'bundle',
|
||||
customTransformOptions: {},
|
||||
deltaBundleId: expect.any(String),
|
||||
dev: true,
|
||||
entryFile: 'index.js',
|
||||
|
@ -245,6 +247,7 @@ describe('processRequest', () => {
|
|||
expect(Serializers.fullBundle).toBeCalledWith(expect.any(DeltaBundler), {
|
||||
assetPlugins: ['assetPlugin1', 'assetPlugin2'],
|
||||
bundleType: 'bundle',
|
||||
customTransformOptions: {},
|
||||
deltaBundleId: expect.any(String),
|
||||
dev: true,
|
||||
entryFile: 'index.js',
|
||||
|
@ -447,6 +450,7 @@ describe('processRequest', () => {
|
|||
expect.any(DeltaBundler),
|
||||
{
|
||||
assetPlugins: [],
|
||||
customTransformOptions: {},
|
||||
deltaBundleId: null,
|
||||
dev: true,
|
||||
entryFile: 'foo file',
|
||||
|
|
|
@ -22,6 +22,8 @@ const formatBundlingError = require('../lib/formatBundlingError');
|
|||
const getMaxWorkers = require('../lib/getMaxWorkers');
|
||||
const getOrderedDependencyPaths = require('../lib/getOrderedDependencyPaths');
|
||||
const mime = require('mime-types');
|
||||
const nullthrows = require('fbjs/lib/nullthrows');
|
||||
const parseCustomTransformOptions = require('../lib/parseCustomTransformOptions');
|
||||
const parsePlatformFilePath = require('../node-haste/lib/parsePlatformFilePath');
|
||||
const path = require('path');
|
||||
const symbolicate = require('./symbolicate');
|
||||
|
@ -762,10 +764,10 @@ class Server {
|
|||
|
||||
_getOptionsFromUrl(reqUrl: string): BundleOptions & DeltaBundlerOptions {
|
||||
// `true` to parse the query param as an object.
|
||||
const urlObj = url.parse(reqUrl, true);
|
||||
const urlObj = nullthrows(url.parse(reqUrl, true));
|
||||
const urlQuery = nullthrows(urlObj.query);
|
||||
|
||||
/* $FlowFixMe: `pathname` could be empty for an invalid URL */
|
||||
const pathname = decodeURIComponent(urlObj.pathname);
|
||||
const pathname = urlObj.pathname ? decodeURIComponent(urlObj.pathname) : '';
|
||||
|
||||
let isMap = false;
|
||||
|
||||
|
@ -795,38 +797,38 @@ class Server {
|
|||
|
||||
// try to get the platform from the url
|
||||
const platform =
|
||||
/* $FlowFixMe: `query` could be empty for an invalid URL */
|
||||
urlObj.query.platform ||
|
||||
urlQuery.platform ||
|
||||
parsePlatformFilePath(pathname, this._platforms).platform;
|
||||
|
||||
/* $FlowFixMe: `query` could be empty for an invalid URL */
|
||||
const deltaBundleId = urlObj.query.deltaBundleId;
|
||||
const deltaBundleId = urlQuery.deltaBundleId;
|
||||
|
||||
/* $FlowFixMe: `query` could be empty for an invalid URL */
|
||||
const assetPlugin = urlObj.query.assetPlugin;
|
||||
const assetPlugin = urlQuery.assetPlugin;
|
||||
const assetPlugins = Array.isArray(assetPlugin)
|
||||
? assetPlugin
|
||||
: typeof assetPlugin === 'string' ? [assetPlugin] : [];
|
||||
|
||||
const dev = this._getBoolOptionFromQuery(urlObj.query, 'dev', true);
|
||||
const minify = this._getBoolOptionFromQuery(urlObj.query, 'minify', false);
|
||||
const dev = this._getBoolOptionFromQuery(urlQuery, 'dev', true);
|
||||
const minify = this._getBoolOptionFromQuery(urlQuery, 'minify', false);
|
||||
const excludeSource = this._getBoolOptionFromQuery(
|
||||
urlObj.query,
|
||||
urlQuery,
|
||||
'excludeSource',
|
||||
false,
|
||||
);
|
||||
const includeSource = this._getBoolOptionFromQuery(
|
||||
urlObj.query,
|
||||
urlQuery,
|
||||
'inlineSourceMap',
|
||||
false,
|
||||
);
|
||||
|
||||
const customTransformOptions = parseCustomTransformOptions(urlObj);
|
||||
|
||||
return {
|
||||
sourceMapUrl: url.format({
|
||||
...urlObj,
|
||||
pathname: pathname.replace(/\.(bundle|delta)$/, '.map'),
|
||||
}),
|
||||
bundleType: isMap ? 'map' : deltaBundleId ? 'delta' : 'bundle',
|
||||
customTransformOptions,
|
||||
entryFile,
|
||||
deltaBundleId,
|
||||
dev,
|
||||
|
@ -873,6 +875,7 @@ class Server {
|
|||
|
||||
static DEFAULT_BUNDLE_OPTIONS = {
|
||||
assetPlugins: [],
|
||||
customTransformOptions: Object.create(null),
|
||||
dev: true,
|
||||
entryModuleOnly: false,
|
||||
excludeSource: false,
|
||||
|
|
|
@ -24,6 +24,7 @@ const path = require('path');
|
|||
const throat = require('throat');
|
||||
|
||||
import type {
|
||||
CustomTransformOptions,
|
||||
Options as TransformWorkerOptions,
|
||||
TransformOptionsStrict,
|
||||
} from '../JSTransformer/worker';
|
||||
|
@ -440,6 +441,7 @@ class OptionsHasher {
|
|||
): crypto$Hash {
|
||||
const {
|
||||
assetDataPlugins,
|
||||
customTransformOptions,
|
||||
enableBabelRCLookup,
|
||||
dev,
|
||||
hot,
|
||||
|
@ -472,6 +474,9 @@ class OptionsHasher {
|
|||
hash.update(JSON.stringify(assetDataPlugins));
|
||||
hash.update(JSON.stringify(platform));
|
||||
hash.update(JSON.stringify(this.toLocalPath(projectRoot)));
|
||||
hash.update(
|
||||
JSON.stringify(this.sortTransformOptions(customTransformOptions || {})),
|
||||
);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
@ -483,6 +488,14 @@ class OptionsHasher {
|
|||
toLocalPath(filePath: string): string {
|
||||
return path.relative(this._rootPath, filePath);
|
||||
}
|
||||
|
||||
sortTransformOptions(
|
||||
options: CustomTransformOptions,
|
||||
): Array<[string, mixed]> {
|
||||
return Object.keys(options)
|
||||
.sort()
|
||||
.map(key => [key, options[key]]);
|
||||
}
|
||||
}
|
||||
|
||||
class CannotHashOptionsError extends Error {
|
||||
|
|
|
@ -19,12 +19,12 @@ Object {
|
|||
exports[`GlobalTransformCache fetches results 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"code": "/* code from http://globalcache.com/a00af5f7803566564fc1e5bd209552899c7354e1-foo.js */",
|
||||
"code": "/* code from http://globalcache.com/3b3b861b6b80dd038c51262ca8b8b9f76e353ada-foo.js */",
|
||||
"dependencies": Array [],
|
||||
"dependencyOffsets": Array [],
|
||||
},
|
||||
Object {
|
||||
"code": "/* code from http://globalcache.com/50013dd319b49a40f1b3d325be62320a4c2a6c82-bar.js */",
|
||||
"code": "/* code from http://globalcache.com/087b5bc3467f9a0670e49ce9118e6f6791aa12c6-bar.js */",
|
||||
"dependencies": Array [],
|
||||
"dependencyOffsets": Array [],
|
||||
},
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @emails oncall+javascript_foundation
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const parseCustomTransformOptions = require('../parseCustomTransformOptions');
|
||||
const url = require('url');
|
||||
|
||||
it('should parse some custom options from a http url', () => {
|
||||
const myUrl =
|
||||
'http://localhost/my/bundle.bundle?dev=true&transform.foo=value&transform.bar=other';
|
||||
|
||||
expect(parseCustomTransformOptions(url.parse(myUrl, true))).toEqual({
|
||||
foo: 'value',
|
||||
bar: 'other',
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse some custom options from a websocket url', () => {
|
||||
const myUrl = 'ws://localhost/hot?transform.foo=value&transform.bar=other';
|
||||
|
||||
expect(parseCustomTransformOptions(url.parse(myUrl, true))).toEqual({
|
||||
foo: 'value',
|
||||
bar: 'other',
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an empty object if there are no custom params', () => {
|
||||
const myUrl = 'http://localhost/my/bundle.bundle?dev=true';
|
||||
|
||||
expect(parseCustomTransformOptions(url.parse(myUrl, true))).toEqual({});
|
||||
});
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @emails oncall+javascript_foundation
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const nullthrows = require('fbjs/lib/nullthrows');
|
||||
|
||||
import type {CustomTransformOptions} from '../JSTransformer/worker';
|
||||
|
||||
const PREFIX = 'transform.';
|
||||
|
||||
module.exports = function parseCustomTransformOptions(urlObj: {
|
||||
query?: {[string]: string},
|
||||
}): CustomTransformOptions {
|
||||
const customTransformOptions = Object.create(null);
|
||||
const query = nullthrows(urlObj.query);
|
||||
|
||||
Object.keys(query).forEach(key => {
|
||||
if (key.startsWith(PREFIX)) {
|
||||
customTransformOptions[key.substr(PREFIX.length)] = query[key];
|
||||
}
|
||||
});
|
||||
|
||||
return customTransformOptions;
|
||||
};
|
|
@ -17,6 +17,7 @@ import type {
|
|||
PostProcessBundleSourcemap,
|
||||
} from '../Bundler';
|
||||
import type {PostProcessModules} from '../DeltaBundler';
|
||||
import type {CustomTransformOptions} from '../JSTransformer/worker';
|
||||
import type {DynamicRequiresBehavior} from '../ModuleGraph/worker/collectDependencies';
|
||||
import type {GlobalTransformCache} from '../lib/GlobalTransformCache';
|
||||
import type {TransformCache} from '../lib/TransformCaching';
|
||||
|
@ -34,6 +35,7 @@ type MetroSourceMapOrMappings =
|
|||
export type BundleOptions = {
|
||||
+assetPlugins: Array<string>,
|
||||
bundleType: BundleType,
|
||||
customTransformOptions: CustomTransformOptions,
|
||||
dev: boolean,
|
||||
entryFile: string,
|
||||
+entryModuleOnly: boolean,
|
||||
|
|
Loading…
Reference in New Issue