diff --git a/desktop/flipper-ui-browser/src/initializeRenderHost.tsx b/desktop/flipper-ui-browser/src/initializeRenderHost.tsx index b6a50d014..c15f87505 100644 --- a/desktop/flipper-ui-browser/src/initializeRenderHost.tsx +++ b/desktop/flipper-ui-browser/src/initializeRenderHost.tsx @@ -7,8 +7,8 @@ * @format */ -import {FlipperServer, FlipperServerConfig} from 'flipper-common'; -import {RenderHost} from 'flipper-ui-core'; +import {FlipperServer, FlipperServerConfig, isProduction} from 'flipper-common'; +import type {RenderHost} from 'flipper-ui-core'; export function initializeRenderHost( flipperServer: FlipperServer, @@ -79,6 +79,12 @@ export function initializeRenderHost( // the 'static' folder is mounted as static middleware in Express at the root return '/' + path; }, + getLocalIconUrl(icon, url) { + if (isProduction()) { + return `icons/${icon.name}-${icon.variant}-${icon.size}@${icon.density}x.png`; + } + return url; + }, } as RenderHost; } diff --git a/desktop/scripts/build-flipper-server-release.ts b/desktop/scripts/build-flipper-server-release.ts index 34c165523..7b86c8484 100644 --- a/desktop/scripts/build-flipper-server-release.ts +++ b/desktop/scripts/build-flipper-server-release.ts @@ -24,9 +24,7 @@ import { import isFB from './isFB'; import yargs from 'yargs'; import fs from 'fs-extra'; -import copyPackageWithDependencies, { - copyPackageWithDependenciesRecursive, -} from './copy-package-with-dependencies'; +import {downloadIcons} from './build-icons'; const argv = yargs .usage('yarn build-flipper-server [args]') @@ -115,6 +113,7 @@ if (argv['enabled-plugins'] !== undefined) { await compileServerMain(false); await buildBrowserBundle(false); await copyStaticResources(); + await downloadIcons(serverStaticDir); if (argv.open) { await launchServer(false, true); diff --git a/desktop/scripts/build-icons.ts b/desktop/scripts/build-icons.ts new file mode 100644 index 000000000..a2e1573f9 --- /dev/null +++ b/desktop/scripts/build-icons.ts @@ -0,0 +1,96 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import path from 'path'; +import fs from 'fs-extra'; +import fetch from '@adobe/node-fetch-retry'; +// eslint-disable-next-line node/no-extraneous-import +import type {Icon} from 'flipper-ui-core'; + +export type Icons = { + [key: string]: Icon['size'][]; +}; + +// Takes a string like 'star', or 'star-outline', and converts it to +// {trimmedName: 'star', variant: 'filled'} or {trimmedName: 'star', variant: 'outline'} +function getIconPartsFromName(icon: string): { + trimmedName: string; + variant: 'outline' | 'filled'; +} { + const isOutlineVersion = icon.endsWith('-outline'); + const trimmedName = isOutlineVersion ? icon.replace('-outline', '') : icon; + const variant = isOutlineVersion ? 'outline' : 'filled'; + return {trimmedName: trimmedName, variant: variant}; +} + +export async function downloadIcons(buildFolder: string) { + const icons: Icons = JSON.parse( + await fs.promises.readFile(path.join(buildFolder, 'icons.json'), { + encoding: 'utf8', + }), + ); + const iconURLs = Object.entries(icons).reduce( + (acc, [entryName, sizes]) => { + const {trimmedName: name, variant} = getIconPartsFromName(entryName); + acc.push( + // get icons in @1x and @2x + ...sizes.map((size) => ({name, variant, size, density: 1})), + ...sizes.map((size) => ({name, variant, size, density: 2})), + ); + return acc; + }, + [], + ); + + return Promise.all( + iconURLs.map((icon) => { + const url = getPublicIconUrl(icon); + return fetch(url, { + retryOptions: { + // Be default, only 5xx are retried but we're getting the odd 404 + // which goes away on a retry for some reason. + retryOnHttpResponse: (res) => res.status >= 400, + }, + }) + .then((res) => { + if (res.status !== 200) { + throw new Error( + // eslint-disable-next-line prettier/prettier + `Could not download the icon ${icon} from ${url}: got status ${res.status}`, + ); + } + return res; + }) + .then( + (res) => + new Promise((resolve, reject) => { + const fileStream = fs.createWriteStream( + path.join(buildFolder, buildLocalIconPath(icon)), + ); + res.body.pipe(fileStream); + res.body.on('error', reject); + fileStream.on('finish', resolve); + }), + ); + }), + ); +} + +// should match flipper-ui-core/src/utils/icons.tsx +export function getPublicIconUrl({name, variant, size, density}: Icon) { + return `https://facebook.com/assets/?name=${name}&variant=${variant}&size=${size}&set=facebook_icons&density=${density}x`; +} + +// should match app/src/utils/icons.tsx +function buildLocalIconPath(icon: Icon) { + return path.join( + 'icons', + `${icon.name}-${icon.variant}-${icon.size}@${icon.density}x.png`, + ); +} diff --git a/desktop/scripts/build-release.ts b/desktop/scripts/build-release.ts index 5a163cc22..c532bae71 100755 --- a/desktop/scripts/build-release.ts +++ b/desktop/scripts/build-release.ts @@ -28,14 +28,12 @@ import { prepareDefaultPlugins, moveSourceMaps, } from './build-utils'; -import fetch from '@adobe/node-fetch-retry'; import isFB from './isFB'; import copyPackageWithDependencies from './copy-package-with-dependencies'; -import {staticDir, distDir, defaultPluginsDir} from './paths'; +import {staticDir, distDir} from './paths'; import yargs from 'yargs'; import {WinPackager} from 'app-builder-lib/out/winPackager'; -// eslint-disable-next-line node/no-extraneous-import -import type {Icon} from 'flipper-ui-core'; +import {downloadIcons} from './build-icons'; // Used in some places to avoid release-to-release changes. Needs // to be this high for some MacOS-specific things that I can't @@ -307,71 +305,6 @@ async function copyStaticFolder(buildFolder: string) { console.log('✅ Copied static package with dependencies.'); } -// Takes a string like 'star', or 'star-outline', and converts it to -// {trimmedName: 'star', variant: 'filled'} or {trimmedName: 'star', variant: 'outline'} -function getIconPartsFromName(icon: string): { - trimmedName: string; - variant: 'outline' | 'filled'; -} { - const isOutlineVersion = icon.endsWith('-outline'); - const trimmedName = isOutlineVersion ? icon.replace('-outline', '') : icon; - const variant = isOutlineVersion ? 'outline' : 'filled'; - return {trimmedName: trimmedName, variant: variant}; -} - -async function downloadIcons(buildFolder: string) { - const icons: Icons = JSON.parse( - await fs.promises.readFile(path.join(buildFolder, 'icons.json'), { - encoding: 'utf8', - }), - ); - const iconURLs = Object.entries(icons).reduce( - (acc, [entryName, sizes]) => { - const {trimmedName: name, variant} = getIconPartsFromName(entryName); - acc.push( - // get icons in @1x and @2x - ...sizes.map((size) => ({name, variant, size, density: 1})), - ...sizes.map((size) => ({name, variant, size, density: 2})), - ); - return acc; - }, - [], - ); - - return Promise.all( - iconURLs.map((icon) => { - const url = getPublicIconUrl(icon); - return fetch(url, { - retryOptions: { - // Be default, only 5xx are retried but we're getting the odd 404 - // which goes away on a retry for some reason. - retryOnHttpResponse: (res) => res.status >= 400, - }, - }) - .then((res) => { - if (res.status !== 200) { - throw new Error( - // eslint-disable-next-line prettier/prettier - `Could not download the icon ${icon} from ${url}: got status ${res.status}`, - ); - } - return res; - }) - .then( - (res) => - new Promise((resolve, reject) => { - const fileStream = fs.createWriteStream( - path.join(buildFolder, buildLocalIconPath(icon)), - ); - res.body.pipe(fileStream); - res.body.on('error', reject); - fileStream.on('finish', resolve); - }), - ); - }), - ); -} - (async () => { const dir = await buildFolder(); // eslint-disable-next-line no-console @@ -393,20 +326,3 @@ async function downloadIcons(buildFolder: string) { console.log('✨ Done'); process.exit(); })(); - -export type Icons = { - [key: string]: Icon['size'][]; -}; - -// should match flipper-ui-core/src/utils/icons.tsx -export function getPublicIconUrl({name, variant, size, density}: Icon) { - return `https://facebook.com/assets/?name=${name}&variant=${variant}&size=${size}&set=facebook_icons&density=${density}x`; -} - -// should match app/src/utils/icons.tsx -function buildLocalIconPath(icon: Icon) { - return path.join( - 'icons', - `${icon.name}-${icon.variant}-${icon.size}@${icon.density}x.png`, - ); -}