Fix generation of bundled.json, make source maps work in prod builds
Summary: This diff fixes several issues around loading plugin, such as: * make suresource maps work in the flipper-server production build * make sure default plugins are no symlinked, which wouldn't work anywhere else but on the the system where it was build * support release channel param for flipper-server Bundled flipper-server is now 42MB (with icons (see later diffs) and plugins ``` ll flipper-server-v0.0.0.tgz -rw-r--r-- 1 mweststrate staff 42M 23 Dec 15:29 flipper-server-v0.0.0.tgz ``` Reviewed By: nikoant Differential Revision: D33294677 fbshipit-source-id: 63538dc8127f883fee6a3608673ad11ce239b350
This commit is contained in:
committed by
Facebook GitHub Bot
parent
b1d960e4c4
commit
72fa481d27
@@ -81,6 +81,9 @@ export class FlipperServerImpl implements FlipperServer {
|
|||||||
keytarModule?: KeytarModule,
|
keytarModule?: KeytarModule,
|
||||||
) {
|
) {
|
||||||
setFlipperServerConfig(config);
|
setFlipperServerConfig(config);
|
||||||
|
console.log(
|
||||||
|
'Loaded flipper config, paths: ' + JSON.stringify(config.paths, null, 2),
|
||||||
|
);
|
||||||
const server = (this.server = new ServerController(this));
|
const server = (this.server = new ServerController(this));
|
||||||
this.android = new AndroidDeviceManager(this);
|
this.android = new AndroidDeviceManager(this);
|
||||||
this.ios = new IOSDeviceManager(this);
|
this.ios = new IOSDeviceManager(this);
|
||||||
|
|||||||
@@ -45,6 +45,11 @@ export async function loadDynamicPlugins(): Promise<InstalledPluginDetails[]> {
|
|||||||
)
|
)
|
||||||
).map((p: any) => p.name) as string[],
|
).map((p: any) => p.name) as string[],
|
||||||
);
|
);
|
||||||
|
console.log(
|
||||||
|
`✅ Detected ${bundledPlugins.size} bundled plugins: ${Array.from(
|
||||||
|
bundledPlugins,
|
||||||
|
).join(', ')}.`,
|
||||||
|
);
|
||||||
const [installedPlugins, unfilteredSourcePlugins] = await Promise.all([
|
const [installedPlugins, unfilteredSourcePlugins] = await Promise.all([
|
||||||
process.env.FLIPPER_NO_PLUGIN_MARKETPLACE
|
process.env.FLIPPER_NO_PLUGIN_MARKETPLACE
|
||||||
? Promise.resolve([])
|
? Promise.resolve([])
|
||||||
@@ -60,23 +65,23 @@ export async function loadDynamicPlugins(): Promise<InstalledPluginDetails[]> {
|
|||||||
const defaultPlugins = await getAllInstalledPluginsInDir(defaultPluginsDir);
|
const defaultPlugins = await getAllInstalledPluginsInDir(defaultPluginsDir);
|
||||||
if (defaultPlugins.length > 0) {
|
if (defaultPlugins.length > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
`✅ Loaded ${defaultPlugins.length} default plugins: ${defaultPlugins
|
`✅ Loaded ${defaultPlugins.length} default plugins:\n${defaultPlugins
|
||||||
.map((x) => x.title)
|
.map((x) => `${x.title}@${x.version}`)
|
||||||
.join(', ')}.`,
|
.join('\n')}.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (installedPlugins.length > 0) {
|
if (installedPlugins.length > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
`✅ Loaded ${installedPlugins.length} installed plugins: ${Array.from(
|
`✅ Loaded ${installedPlugins.length} installed plugins:\n${Array.from(
|
||||||
new Set(installedPlugins.map((x) => x.title)),
|
new Set(installedPlugins.map((x) => `${x.title}@${x.version}`)),
|
||||||
).join(', ')}.`,
|
).join('\n')}.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (sourcePlugins.length > 0) {
|
if (sourcePlugins.length > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
`✅ Loaded ${sourcePlugins.length} source plugins: ${sourcePlugins
|
`✅ Loaded ${sourcePlugins.length} source plugins:\n${sourcePlugins
|
||||||
.map((x) => x.title)
|
.map((x) => `${x.title} - ${x.dir}`)
|
||||||
.join(', ')}.`,
|
.join('\n')}.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return [...defaultPlugins, ...installedPlugins, ...sourcePlugins];
|
return [...defaultPlugins, ...installedPlugins, ...sourcePlugins];
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import pFilter from 'p-filter';
|
|||||||
import {homedir} from 'os';
|
import {homedir} from 'os';
|
||||||
|
|
||||||
// This file is heavily inspired by scripts/start-dev-server.ts!
|
// This file is heavily inspired by scripts/start-dev-server.ts!
|
||||||
// part of that is done by start-flipper-server (compiling "main"),
|
// part of that is done by start-flipper-server-dev (compiling "main"),
|
||||||
// the other part ("renderer") here.
|
// the other part ("renderer") here.
|
||||||
|
|
||||||
const uiSourceDirs = [
|
const uiSourceDirs = [
|
||||||
|
|||||||
@@ -59,10 +59,18 @@ export function initializeRenderHost(
|
|||||||
},
|
},
|
||||||
flipperServer,
|
flipperServer,
|
||||||
async requirePlugin(path) {
|
async requirePlugin(path) {
|
||||||
// TODO: use `await import(path)`?
|
let source = await flipperServer.exec('plugin-source', path);
|
||||||
const source = await flipperServer.exec('plugin-source', path);
|
// append source url (to make sure a file entry shows up in the debugger)
|
||||||
// eslint-disable-next-line no-new-func
|
source += `\n//# sourceURL=file://${path}`;
|
||||||
const cjsLoader = new Function('module', source);
|
// and source map url (to get source code if available)
|
||||||
|
source += `\n//# sourceMappingURL=file://${path.replace(/.js$/, '.map')}`;
|
||||||
|
|
||||||
|
// Plugins are compiled as typical CJS modules, referring to the global
|
||||||
|
// 'module', which we'll make available by loading the source into a closure that captures 'module'.
|
||||||
|
// Note that we use 'eval', and not 'new Function', because the latter will cause the source maps
|
||||||
|
// to be off by two lines (as the function declaration uses two lines in the generated source)
|
||||||
|
// eslint-disable-next-line no-eval
|
||||||
|
const cjsLoader = eval('(module) => {' + source + '\n}');
|
||||||
const theModule = {exports: {}};
|
const theModule = {exports: {}};
|
||||||
cjsLoader(theModule);
|
cjsLoader(theModule);
|
||||||
return theModule.exports;
|
return theModule.exports;
|
||||||
|
|||||||
@@ -128,7 +128,7 @@
|
|||||||
"predev-server": "yarn build:tsc",
|
"predev-server": "yarn build:tsc",
|
||||||
"dev-server": "cross-env NODE_ENV=development ./ts-node scripts/start-dev-server.ts",
|
"dev-server": "cross-env NODE_ENV=development ./ts-node scripts/start-dev-server.ts",
|
||||||
"preflipper-server": "yarn build:tsc",
|
"preflipper-server": "yarn build:tsc",
|
||||||
"flipper-server": "cross-env NODE_ENV=development ./ts-node scripts/start-flipper-server.ts",
|
"flipper-server": "cross-env NODE_ENV=development ./ts-node scripts/start-flipper-server-dev.ts",
|
||||||
"fix": "eslint . --fix --ext .js,.ts,.tsx",
|
"fix": "eslint . --fix --ext .js,.ts,.tsx",
|
||||||
"lint": "yarn lint:eslint && yarn lint:tsc && yarn tsc-plugins",
|
"lint": "yarn lint:eslint && yarn lint:tsc && yarn tsc-plugins",
|
||||||
"lint:eslint": "eslint . --ext .js,.ts,.tsx",
|
"lint:eslint": "eslint . --ext .js,.ts,.tsx",
|
||||||
|
|||||||
@@ -15,10 +15,18 @@ import {
|
|||||||
launchServer,
|
launchServer,
|
||||||
prepareDefaultPlugins,
|
prepareDefaultPlugins,
|
||||||
} from './build-utils';
|
} from './build-utils';
|
||||||
import {serverStaticDir, staticDir} from './paths';
|
import {
|
||||||
|
defaultPluginsDir,
|
||||||
|
serverDefaultPluginsDir,
|
||||||
|
serverStaticDir,
|
||||||
|
staticDir,
|
||||||
|
} from './paths';
|
||||||
import isFB from './isFB';
|
import isFB from './isFB';
|
||||||
import yargs from 'yargs';
|
import yargs from 'yargs';
|
||||||
import {copy, mkdir, remove} from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
|
import copyPackageWithDependencies, {
|
||||||
|
copyPackageWithDependenciesRecursive,
|
||||||
|
} from './copy-package-with-dependencies';
|
||||||
|
|
||||||
const argv = yargs
|
const argv = yargs
|
||||||
.usage('yarn build-flipper-server [args]')
|
.usage('yarn build-flipper-server [args]')
|
||||||
@@ -51,6 +59,11 @@ const argv = yargs
|
|||||||
'Load only specified plugins and skip loading rest. This is useful when you are developing only one or few plugins. Plugins to load can be specified as a comma-separated list with either plugin id or name used as identifier, e.g. "--enabled-plugins network,inspector". The flag is not provided by default which means that all plugins loaded.',
|
'Load only specified plugins and skip loading rest. This is useful when you are developing only one or few plugins. Plugins to load can be specified as a comma-separated list with either plugin id or name used as identifier, e.g. "--enabled-plugins network,inspector". The flag is not provided by default which means that all plugins loaded.',
|
||||||
type: 'array',
|
type: 'array',
|
||||||
},
|
},
|
||||||
|
channel: {
|
||||||
|
description: 'Release channel for the build',
|
||||||
|
choices: ['stable', 'insiders'],
|
||||||
|
default: 'stable',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.version('DEV')
|
.version('DEV')
|
||||||
.help()
|
.help()
|
||||||
@@ -60,7 +73,8 @@ if (isFB) {
|
|||||||
process.env.FLIPPER_FB = 'true';
|
process.env.FLIPPER_FB = 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't bundle any plugins into the UI
|
process.env.FLIPPER_RELEASE_CHANNEL = argv.channel;
|
||||||
|
|
||||||
process.env.FLIPPER_NO_BUNDLED_PLUGINS = 'true';
|
process.env.FLIPPER_NO_BUNDLED_PLUGINS = 'true';
|
||||||
|
|
||||||
// Don't rebuild default plugins, mostly to speed up testing
|
// Don't rebuild default plugins, mostly to speed up testing
|
||||||
@@ -93,10 +107,10 @@ if (argv['enabled-plugins'] !== undefined) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// clear and re-create static dir
|
// clear and re-create static dir
|
||||||
await remove(serverStaticDir);
|
await fs.remove(serverStaticDir);
|
||||||
await mkdir(serverStaticDir);
|
await fs.mkdir(serverStaticDir);
|
||||||
|
|
||||||
await prepareDefaultPlugins(false);
|
await prepareDefaultPlugins(argv.channel === 'insiders');
|
||||||
|
|
||||||
await compileServerMain(false);
|
await compileServerMain(false);
|
||||||
await buildBrowserBundle(false);
|
await buildBrowserBundle(false);
|
||||||
@@ -111,11 +125,32 @@ if (argv['enabled-plugins'] !== undefined) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function copyStaticResources() {
|
async function copyStaticResources() {
|
||||||
|
console.log(`⚙️ Copying default plugins...`);
|
||||||
|
await fs.mkdirp(serverDefaultPluginsDir);
|
||||||
|
const plugins = await fs.readdir(defaultPluginsDir);
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
let source = path.join(defaultPluginsDir, plugin);
|
||||||
|
// static/defaultPlugins will symlink, resolve those first
|
||||||
|
while ((await fs.lstat(source)).isSymbolicLink()) {
|
||||||
|
source = await fs.readlink(source);
|
||||||
|
}
|
||||||
|
const target = path.join(serverDefaultPluginsDir, plugin);
|
||||||
|
if ((await fs.stat(source)).isDirectory()) {
|
||||||
|
// for plugins, only copy package.json & dist, to keep impact minimal
|
||||||
|
await fs.copy(
|
||||||
|
path.join(source, 'package.json'),
|
||||||
|
path.join(target, 'package.json'),
|
||||||
|
);
|
||||||
|
await fs.copy(path.join(source, 'dist'), path.join(target, 'dist'));
|
||||||
|
} else {
|
||||||
|
await fs.copy(source, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`⚙️ Copying static resources...`);
|
console.log(`⚙️ Copying static resources...`);
|
||||||
|
|
||||||
// static folder, without the things that are only for Electron
|
// static folder, without the things that are only for Electron
|
||||||
const thingsToCopy = [
|
const thingsToCopy = [
|
||||||
'defaultPlugins',
|
|
||||||
'facebook',
|
'facebook',
|
||||||
'icons',
|
'icons',
|
||||||
'native-modules',
|
'native-modules',
|
||||||
@@ -134,7 +169,7 @@ async function copyStaticResources() {
|
|||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
thingsToCopy.map((e) =>
|
thingsToCopy.map((e) =>
|
||||||
copy(path.join(staticDir, e), path.join(serverStaticDir, e)),
|
fs.copy(path.join(staticDir, e), path.join(serverStaticDir, e)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
console.log('✅ Copied static resources.');
|
console.log('✅ Copied static resources.');
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
import fetch from '@adobe/node-fetch-retry';
|
import fetch from '@adobe/node-fetch-retry';
|
||||||
import isFB from './isFB';
|
import isFB from './isFB';
|
||||||
import copyPackageWithDependencies from './copy-package-with-dependencies';
|
import copyPackageWithDependencies from './copy-package-with-dependencies';
|
||||||
import {staticDir, distDir} from './paths';
|
import {staticDir, distDir, defaultPluginsDir} from './paths';
|
||||||
import yargs from 'yargs';
|
import yargs from 'yargs';
|
||||||
import {WinPackager} from 'app-builder-lib/out/winPackager';
|
import {WinPackager} from 'app-builder-lib/out/winPackager';
|
||||||
// eslint-disable-next-line node/no-extraneous-import
|
// eslint-disable-next-line node/no-extraneous-import
|
||||||
|
|||||||
@@ -420,9 +420,6 @@ export async function compileServerMain(dev: boolean) {
|
|||||||
resetCache: !dev,
|
resetCache: !dev,
|
||||||
});
|
});
|
||||||
console.log('✅ Compiled server bundle.');
|
console.log('✅ Compiled server bundle.');
|
||||||
if (!dev) {
|
|
||||||
stripSourceMapComment(out);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: needed?
|
// TODO: needed?
|
||||||
@@ -503,9 +500,6 @@ export async function buildBrowserBundle(dev: boolean) {
|
|||||||
inlineSourceMap: false,
|
inlineSourceMap: false,
|
||||||
});
|
});
|
||||||
console.log('✅ Compiled browser bundle.');
|
console.log('✅ Compiled browser bundle.');
|
||||||
if (!dev) {
|
|
||||||
stripSourceMapComment(out);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function dedupeFolders(paths: string[]): Promise<string[]> {
|
async function dedupeFolders(paths: string[]): Promise<string[]> {
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ export const staticDir = path.join(rootDir, 'static');
|
|||||||
export const serverDir = path.join(rootDir, 'flipper-server');
|
export const serverDir = path.join(rootDir, 'flipper-server');
|
||||||
export const serverStaticDir = path.join(serverDir, 'static'); // for pre-bundled server, static resources are copied here
|
export const serverStaticDir = path.join(serverDir, 'static'); // for pre-bundled server, static resources are copied here
|
||||||
export const defaultPluginsDir = path.join(staticDir, 'defaultPlugins');
|
export const defaultPluginsDir = path.join(staticDir, 'defaultPlugins');
|
||||||
|
export const serverDefaultPluginsDir = path.join(
|
||||||
|
serverStaticDir,
|
||||||
|
'defaultPlugins',
|
||||||
|
);
|
||||||
export const pluginsDir = path.join(rootDir, 'plugins');
|
export const pluginsDir = path.join(rootDir, 'plugins');
|
||||||
export const fbPluginsDir = path.join(pluginsDir, 'fb');
|
export const fbPluginsDir = path.join(pluginsDir, 'fb');
|
||||||
export const publicPluginsDir = path.join(pluginsDir, 'public');
|
export const publicPluginsDir = path.join(pluginsDir, 'public');
|
||||||
|
|||||||
@@ -65,6 +65,11 @@ const argv = yargs
|
|||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
channel: {
|
||||||
|
description: 'Release channel for the build',
|
||||||
|
choices: ['stable', 'insiders'],
|
||||||
|
default: 'stable',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.version('DEV')
|
.version('DEV')
|
||||||
.help()
|
.help()
|
||||||
@@ -74,6 +79,8 @@ if (isFB) {
|
|||||||
process.env.FLIPPER_FB = 'true';
|
process.env.FLIPPER_FB = 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process.env.FLIPPER_RELEASE_CHANNEL = argv.channel;
|
||||||
|
|
||||||
if (argv['default-plugins'] === true) {
|
if (argv['default-plugins'] === true) {
|
||||||
delete process.env.FLIPPER_NO_DEFAULT_PLUGINS;
|
delete process.env.FLIPPER_NO_DEFAULT_PLUGINS;
|
||||||
} else if (argv['default-plugins'] === false) {
|
} else if (argv['default-plugins'] === false) {
|
||||||
Reference in New Issue
Block a user