From 9581519129d643ce8dafe562d8839daf9d153242 Mon Sep 17 00:00:00 2001 From: Ian Schmitz Date: Mon, 11 Feb 2019 21:05:24 -0800 Subject: [PATCH 1/4] Revert "Revert "Speed up TypeScript projects (#5903)"" This reverts commit 544a5943ce05521b31fa5d347e386ce595079479. --- .../react-dev-utils/WebpackDevServerUtils.js | 116 +++++++++++++++--- .../react-dev-utils/typescriptFormatter.js | 7 +- .../react-dev-utils/webpackHotDevClient.js | 18 +-- .../react-scripts/config/webpack.config.js | 16 +-- packages/react-scripts/package.json | 2 +- packages/react-scripts/scripts/start.js | 17 ++- .../typescript-typecheck/.disable-pnp | 0 .../typescript-typecheck/index.test.js | 33 +++++ .../typescript-typecheck/package.json | 9 ++ .../fixtures/typescript-typecheck/src/App.tsx | 13 ++ .../typescript-typecheck/src/index.tsx | 5 + 11 files changed, 193 insertions(+), 43 deletions(-) create mode 100644 test/fixtures/typescript-typecheck/.disable-pnp create mode 100644 test/fixtures/typescript-typecheck/index.test.js create mode 100644 test/fixtures/typescript-typecheck/package.json create mode 100644 test/fixtures/typescript-typecheck/src/App.tsx create mode 100644 test/fixtures/typescript-typecheck/src/index.tsx diff --git a/packages/react-dev-utils/WebpackDevServerUtils.js b/packages/react-dev-utils/WebpackDevServerUtils.js index 67a1a45e3a6..67f6d4164f7 100644 --- a/packages/react-dev-utils/WebpackDevServerUtils.js +++ b/packages/react-dev-utils/WebpackDevServerUtils.js @@ -17,22 +17,10 @@ const inquirer = require('inquirer'); const clearConsole = require('./clearConsole'); const formatWebpackMessages = require('./formatWebpackMessages'); const getProcessForPort = require('./getProcessForPort'); +const typescriptFormatter = require('./typescriptFormatter'); +const forkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); const isInteractive = process.stdout.isTTY; -let handleCompile; - -// You can safely remove this after ejecting. -// We only use this block for testing of Create React App itself: -const isSmokeTest = process.argv.some(arg => arg.indexOf('--smoke-test') > -1); -if (isSmokeTest) { - handleCompile = (err, stats) => { - if (err || stats.hasErrors() || stats.hasWarnings()) { - process.exit(1); - } else { - process.exit(0); - } - }; -} function prepareUrls(protocol, host, port) { const formatUrl = hostname => @@ -113,12 +101,20 @@ function printInstructions(appName, urls, useYarn) { console.log(); } -function createCompiler(webpack, config, appName, urls, useYarn) { +function createCompiler( + webpack, + config, + appName, + urls, + useYarn, + useTypeScript, + devSocket +) { // "Compiler" is a low-level interface to Webpack. // It lets us listen to some events and provide our own custom messages. let compiler; try { - compiler = webpack(config, handleCompile); + compiler = webpack(config); } catch (err) { console.log(chalk.red('Failed to compile.')); console.log(); @@ -139,10 +135,35 @@ function createCompiler(webpack, config, appName, urls, useYarn) { }); let isFirstCompile = true; + let tsMessagesPromise; + let tsMessagesResolver; + + if (useTypeScript) { + compiler.hooks.beforeCompile.tap('beforeCompile', () => { + tsMessagesPromise = new Promise(resolve => { + tsMessagesResolver = msgs => resolve(msgs); + }); + }); + + forkTsCheckerWebpackPlugin + .getCompilerHooks(compiler) + .receive.tap('afterTypeScriptCheck', (diagnostics, lints) => { + const allMsgs = [...diagnostics, ...lints]; + const format = message => + `${message.file}\n${typescriptFormatter(message, true)}`; + + tsMessagesResolver({ + errors: allMsgs.filter(msg => msg.severity === 'error').map(format), + warnings: allMsgs + .filter(msg => msg.severity === 'warning') + .map(format), + }); + }); + } // "done" event fires when Webpack has finished recompiling the bundle. // Whether or not you have warnings or errors, you will get this event. - compiler.hooks.done.tap('done', stats => { + compiler.hooks.done.tap('done', async stats => { if (isInteractive) { clearConsole(); } @@ -152,9 +173,43 @@ function createCompiler(webpack, config, appName, urls, useYarn) { // them in a readable focused way. // We only construct the warnings and errors for speed: // https://github.com/facebook/create-react-app/issues/4492#issuecomment-421959548 - const messages = formatWebpackMessages( - stats.toJson({ all: false, warnings: true, errors: true }) - ); + const statsData = stats.toJson({ + all: false, + warnings: true, + errors: true, + }); + + if (useTypeScript && statsData.errors.length === 0) { + const delayedMsg = setTimeout(() => { + console.log( + chalk.yellow( + 'Files successfully emitted, waiting for typecheck results...' + ) + ); + }, 100); + + const messages = await tsMessagesPromise; + clearTimeout(delayedMsg); + statsData.errors.push(...messages.errors); + statsData.warnings.push(...messages.warnings); + + // Push errors and warnings into compilation result + // to show them after page refresh triggered by user. + stats.compilation.errors.push(...messages.errors); + stats.compilation.warnings.push(...messages.warnings); + + if (messages.errors.length > 0) { + devSocket.errors(messages.errors); + } else if (messages.warnings.length > 0) { + devSocket.warnings(messages.warnings); + } + + if (isInteractive) { + clearConsole(); + } + } + + const messages = formatWebpackMessages(statsData); const isSuccessful = !messages.errors.length && !messages.warnings.length; if (isSuccessful) { console.log(chalk.green('Compiled successfully!')); @@ -194,6 +249,27 @@ function createCompiler(webpack, config, appName, urls, useYarn) { ); } }); + + // You can safely remove this after ejecting. + // We only use this block for testing of Create React App itself: + const isSmokeTest = process.argv.some( + arg => arg.indexOf('--smoke-test') > -1 + ); + if (isSmokeTest) { + compiler.hooks.failed.tap('smokeTest', async () => { + await tsMessagesPromise; + process.exit(1); + }); + compiler.hooks.done.tap('smokeTest', async stats => { + await tsMessagesPromise; + if (stats.hasErrors() || stats.hasWarnings()) { + process.exit(1); + } else { + process.exit(0); + } + }); + } + return compiler; } diff --git a/packages/react-dev-utils/typescriptFormatter.js b/packages/react-dev-utils/typescriptFormatter.js index 2d011fc7e71..3a33b37a427 100644 --- a/packages/react-dev-utils/typescriptFormatter.js +++ b/packages/react-dev-utils/typescriptFormatter.js @@ -45,12 +45,15 @@ function formatter(message, useColors) { } const severity = hasGetters ? message.getSeverity() : message.severity; + const types = { diagnostic: 'TypeScript', lint: 'TSLint' }; return [ - messageColor.bold(`Type ${severity.toLowerCase()}: `) + + messageColor.bold(`${types[message.type]} ${severity.toLowerCase()}: `) + (hasGetters ? message.getContent() : message.content) + ' ' + - messageColor.underline(`TS${message.code}`), + messageColor.underline( + (message.type === 'lint' ? 'Rule: ' : 'TS') + message.code + ), '', frame, ].join(os.EOL); diff --git a/packages/react-dev-utils/webpackHotDevClient.js b/packages/react-dev-utils/webpackHotDevClient.js index cc7dc61684b..050ce2a6351 100644 --- a/packages/react-dev-utils/webpackHotDevClient.js +++ b/packages/react-dev-utils/webpackHotDevClient.js @@ -106,7 +106,7 @@ function handleSuccess() { tryApplyUpdates(function onHotUpdateSuccess() { // Only dismiss it when we're sure it's a hot update. // Otherwise it would flicker right before the reload. - ErrorOverlay.dismissBuildError(); + tryDismissErrorOverlay(); }); } } @@ -140,19 +140,15 @@ function handleWarnings(warnings) { } } + printWarnings(); + // Attempt to apply hot updates or reload. if (isHotUpdate) { tryApplyUpdates(function onSuccessfulHotUpdate() { - // Only print warnings if we aren't refreshing the page. - // Otherwise they'll disappear right away anyway. - printWarnings(); // Only dismiss it when we're sure it's a hot update. // Otherwise it would flicker right before the reload. - ErrorOverlay.dismissBuildError(); + tryDismissErrorOverlay(); }); - } else { - // Print initial warnings immediately. - printWarnings(); } } @@ -183,6 +179,12 @@ function handleErrors(errors) { // We will reload on next success instead. } +function tryDismissErrorOverlay() { + if (!hasCompileErrors) { + ErrorOverlay.dismissBuildError(); + } +} + // There is a newer version of the code available. function handleAvailableHash(hash) { // Update last known compilation hash. diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index 71c0b750f83..9781875bd30 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -29,7 +29,7 @@ const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent') const paths = require('./paths'); const getClientEnvironment = require('./env'); const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); -const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin-alt'); +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); const typescriptFormatter = require('react-dev-utils/typescriptFormatter'); // @remove-on-eject-begin const getCacheIdentifier = require('react-dev-utils/getCacheIdentifier'); @@ -625,17 +625,10 @@ module.exports = function(webpackEnv) { typescript: resolve.sync('typescript', { basedir: paths.appNodeModules, }), - async: false, + async: isEnvDevelopment, + useTypescriptIncrementalApi: true, checkSyntacticErrors: true, tsconfig: paths.appTsConfig, - compilerOptions: { - module: 'esnext', - moduleResolution: 'node', - resolveJsonModule: true, - isolatedModules: true, - noEmit: true, - jsx: 'preserve', - }, reportFiles: [ '**', '!**/*.json', @@ -646,7 +639,8 @@ module.exports = function(webpackEnv) { ], watch: paths.appSrc, silent: true, - formatter: typescriptFormatter, + // The formatter is invoked directly in WebpackDevServerUtils during development + formatter: isEnvProduction ? typescriptFormatter : undefined, }), ].filter(Boolean), // Some libraries import Node modules but don't use them in the browser. diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index 93e4d4d2d18..2d6e0c55c04 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -45,7 +45,7 @@ "eslint-plugin-jsx-a11y": "6.1.2", "eslint-plugin-react": "7.12.4", "file-loader": "2.0.0", - "fork-ts-checker-webpack-plugin-alt": "0.4.14", + "fork-ts-checker-webpack-plugin": "1.0.0-alpha.6", "fs-extra": "7.0.1", "html-webpack-plugin": "4.0.0-alpha.2", "identity-obj-proxy": "3.0.0", diff --git a/packages/react-scripts/scripts/start.js b/packages/react-scripts/scripts/start.js index 852e6b8fb44..6ad020c9d46 100644 --- a/packages/react-scripts/scripts/start.js +++ b/packages/react-scripts/scripts/start.js @@ -94,9 +94,24 @@ checkBrowsers(paths.appPath, isInteractive) const config = configFactory('development'); const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; const appName = require(paths.appPackageJson).name; + const useTypeScript = fs.existsSync(paths.appTsConfig); const urls = prepareUrls(protocol, HOST, port); + const devSocket = { + warnings: warnings => + devServer.sockWrite(devServer.sockets, 'warnings', warnings), + errors: errors => + devServer.sockWrite(devServer.sockets, 'errors', errors), + }; // Create a webpack compiler that is configured with custom messages. - const compiler = createCompiler(webpack, config, appName, urls, useYarn); + const compiler = createCompiler( + webpack, + config, + appName, + urls, + useYarn, + useTypeScript, + devSocket + ); // Load proxy config const proxySetting = require(paths.appPackageJson).proxy; const proxyConfig = prepareProxy(proxySetting, paths.appPublic); diff --git a/test/fixtures/typescript-typecheck/.disable-pnp b/test/fixtures/typescript-typecheck/.disable-pnp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/fixtures/typescript-typecheck/index.test.js b/test/fixtures/typescript-typecheck/index.test.js new file mode 100644 index 00000000000..c4978c735e9 --- /dev/null +++ b/test/fixtures/typescript-typecheck/index.test.js @@ -0,0 +1,33 @@ +const testSetup = require('../__shared__/test-setup'); +const puppeteer = require('puppeteer'); + +const expectedErrorMsg = `Argument of type '123' is not assignable to parameter of type 'string'`; + +test('shows error overlay in browser', async () => { + const { port, done } = await testSetup.scripts.start(); + + const browser = await puppeteer.launch({ headless: true }); + try { + const page = await browser.newPage(); + await page.goto(`http://localhost:${port}/`); + await page.waitForSelector('iframe', { timeout: 5000 }); + const overlayMsg = await page.evaluate(() => { + const overlay = document.querySelector('iframe').contentWindow; + return overlay.document.body.innerHTML; + }); + expect(overlayMsg).toContain(expectedErrorMsg); + } finally { + browser.close(); + done(); + } +}); + +test('shows error in console (dev mode)', async () => { + const { stderr } = await testSetup.scripts.start({ smoke: true }); + expect(stderr).toContain(expectedErrorMsg); +}); + +test('shows error in console (prod mode)', async () => { + const { stderr } = await testSetup.scripts.build(); + expect(stderr).toContain(expectedErrorMsg); +}); diff --git a/test/fixtures/typescript-typecheck/package.json b/test/fixtures/typescript-typecheck/package.json new file mode 100644 index 00000000000..a6c00267c54 --- /dev/null +++ b/test/fixtures/typescript-typecheck/package.json @@ -0,0 +1,9 @@ +{ + "dependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "*", + "react-dom": "*", + "typescript": "3.1.3" + } +} diff --git a/test/fixtures/typescript-typecheck/src/App.tsx b/test/fixtures/typescript-typecheck/src/App.tsx new file mode 100644 index 00000000000..75924d78b0e --- /dev/null +++ b/test/fixtures/typescript-typecheck/src/App.tsx @@ -0,0 +1,13 @@ +import * as React from 'react'; + +class App extends React.Component { + render() { + return
{format(123)}
; + } +} + +function format(value: string) { + return value; +} + +export default App; diff --git a/test/fixtures/typescript-typecheck/src/index.tsx b/test/fixtures/typescript-typecheck/src/index.tsx new file mode 100644 index 00000000000..bea6ed52237 --- /dev/null +++ b/test/fixtures/typescript-typecheck/src/index.tsx @@ -0,0 +1,5 @@ +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import App from './App'; + +ReactDOM.render(, document.getElementById('root')); From 7ecde96e688375f3aae4b187bc8637553d39d05d Mon Sep 17 00:00:00 2001 From: Ian Schmitz Date: Sun, 17 Feb 2019 12:26:04 -0800 Subject: [PATCH 2/4] Move fork-ts-checker dep to react-dev-utils --- .../react-dev-utils/ForkTsCheckerWebpackPlugin.js | 12 ++++++++++++ packages/react-dev-utils/WebpackDevServerUtils.js | 2 +- packages/react-dev-utils/package.json | 4 +++- packages/react-scripts/config/webpack.config.js | 2 +- packages/react-scripts/package.json | 3 +-- 5 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 packages/react-dev-utils/ForkTsCheckerWebpackPlugin.js diff --git a/packages/react-dev-utils/ForkTsCheckerWebpackPlugin.js b/packages/react-dev-utils/ForkTsCheckerWebpackPlugin.js new file mode 100644 index 00000000000..af728e84ff7 --- /dev/null +++ b/packages/react-dev-utils/ForkTsCheckerWebpackPlugin.js @@ -0,0 +1,12 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +var ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); + +module.exports = ForkTsCheckerWebpackPlugin; diff --git a/packages/react-dev-utils/WebpackDevServerUtils.js b/packages/react-dev-utils/WebpackDevServerUtils.js index 67f6d4164f7..fbc6abc0519 100644 --- a/packages/react-dev-utils/WebpackDevServerUtils.js +++ b/packages/react-dev-utils/WebpackDevServerUtils.js @@ -18,7 +18,7 @@ const clearConsole = require('./clearConsole'); const formatWebpackMessages = require('./formatWebpackMessages'); const getProcessForPort = require('./getProcessForPort'); const typescriptFormatter = require('./typescriptFormatter'); -const forkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const forkTsCheckerWebpackPlugin = require('./ForkTsCheckerWebpackPlugin'); const isInteractive = process.stdout.isTTY; diff --git a/packages/react-dev-utils/package.json b/packages/react-dev-utils/package.json index 75990a0efbe..ca7f00ab221 100644 --- a/packages/react-dev-utils/package.json +++ b/packages/react-dev-utils/package.json @@ -8,7 +8,7 @@ "url": "https://github.com/facebook/create-react-app/issues" }, "engines": { - "node": ">=6" + "node": ">=8.10" }, "files": [ "browsersHelper.js", @@ -20,6 +20,7 @@ "eslintFormatter.js", "evalSourceMapMiddleware.js", "FileSizeReporter.js", + "ForkTsCheckerWebpackPlugin.js", "formatWebpackMessages.js", "getCacheIdentifier.js", "getCSSModuleLocalIdent.js", @@ -54,6 +55,7 @@ "escape-string-regexp": "1.0.5", "filesize": "3.6.1", "find-up": "3.0.0", + "fork-ts-checker-webpack-plugin": "1.0.0-alpha.6", "global-modules": "2.0.0", "globby": "8.0.2", "gzip-size": "5.0.0", diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index 9781875bd30..c650dc26c11 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -29,7 +29,7 @@ const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent') const paths = require('./paths'); const getClientEnvironment = require('./env'); const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); -const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin'); const typescriptFormatter = require('react-dev-utils/typescriptFormatter'); // @remove-on-eject-begin const getCacheIdentifier = require('react-dev-utils/getCacheIdentifier'); diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index 2d6e0c55c04..b17fd14ce30 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -5,7 +5,7 @@ "repository": "facebook/create-react-app", "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8.10" }, "bugs": { "url": "https://github.com/facebook/create-react-app/issues" @@ -45,7 +45,6 @@ "eslint-plugin-jsx-a11y": "6.1.2", "eslint-plugin-react": "7.12.4", "file-loader": "2.0.0", - "fork-ts-checker-webpack-plugin": "1.0.0-alpha.6", "fs-extra": "7.0.1", "html-webpack-plugin": "4.0.0-alpha.2", "identity-obj-proxy": "3.0.0", From 007e6fd6190346bf1a74c23a57e2b5a172379f4d Mon Sep 17 00:00:00 2001 From: Ian Schmitz Date: Sun, 17 Feb 2019 12:26:49 -0800 Subject: [PATCH 3/4] Convert WebpackDevServerUtils.createCompiler to take in options arg --- packages/react-dev-utils/WebpackDevServerUtils.js | 10 +++++----- packages/react-scripts/scripts/start.js | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/react-dev-utils/WebpackDevServerUtils.js b/packages/react-dev-utils/WebpackDevServerUtils.js index fbc6abc0519..1d7021e037c 100644 --- a/packages/react-dev-utils/WebpackDevServerUtils.js +++ b/packages/react-dev-utils/WebpackDevServerUtils.js @@ -101,15 +101,15 @@ function printInstructions(appName, urls, useYarn) { console.log(); } -function createCompiler( - webpack, - config, +function createCompiler({ appName, + config, + devSocket, urls, useYarn, useTypeScript, - devSocket -) { + webpack, +}) { // "Compiler" is a low-level interface to Webpack. // It lets us listen to some events and provide our own custom messages. let compiler; diff --git a/packages/react-scripts/scripts/start.js b/packages/react-scripts/scripts/start.js index 6ad020c9d46..807d93d29d0 100644 --- a/packages/react-scripts/scripts/start.js +++ b/packages/react-scripts/scripts/start.js @@ -103,15 +103,15 @@ checkBrowsers(paths.appPath, isInteractive) devServer.sockWrite(devServer.sockets, 'errors', errors), }; // Create a webpack compiler that is configured with custom messages. - const compiler = createCompiler( - webpack, - config, + const compiler = createCompiler({ appName, + config, + devSocket, urls, useYarn, useTypeScript, - devSocket - ); + webpack, + }); // Load proxy config const proxySetting = require(paths.appPackageJson).proxy; const proxyConfig = prepareProxy(proxySetting, paths.appPublic); From 9c48ec6f211d540f22c02e7ce832ce91ae70fbe0 Mon Sep 17 00:00:00 2001 From: Ian Schmitz Date: Mon, 18 Feb 2019 16:07:58 -0800 Subject: [PATCH 4/4] Update README.md for react-dev-utils --- packages/react-dev-utils/README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/react-dev-utils/README.md b/packages/react-dev-utils/README.md index 24d8cce5a4e..9d43182d05e 100644 --- a/packages/react-dev-utils/README.md +++ b/packages/react-dev-utils/README.md @@ -325,9 +325,19 @@ printHostingInstructions(appPackage, publicUrl, publicPath, 'build', true); Returns a Promise resolving to either `defaultPort` or next available port if the user confirms it is okay to do. If the port is taken and the user has refused to use another port, or if the terminal is not interactive and can’t present user with the choice, resolves to `null`. -##### `createCompiler(webpack: Function, config: Object, appName: string, urls: Object, useYarn: boolean): WebpackCompiler` +##### `createCompiler(args: Object): WebpackCompiler` -Creates a Webpack compiler instance for WebpackDevServer with built-in helpful messages. Takes the `require('webpack')` entry point as the first argument. To provide the `urls` argument, use `prepareUrls()` described below. +Creates a Webpack compiler instance for WebpackDevServer with built-in helpful messages. + +The `args` object accepts a number of properties: + +- **appName** `string`: The name that will be printed to the terminal. +- **config** `Object`: The webpack configuration options to be provided to the webpack constructor. +- **devSocket** `Object`: Required if `useTypeScript` is `true`. This object should include `errors` and `warnings` which are functions accepting an array of errors or warnings emitted by the type checking. This is useful when running `fork-ts-checker-webpack-plugin` with `async: true` to report errors that are emitted after the webpack build is complete. +- **urls** `Object`: To provide the `urls` argument, use `prepareUrls()` described below. +- **useYarn** `boolean`: If `true`, yarn instructions will be emitted in the terminal instead of npm. +- **useTypeScript** `boolean`: If `true`, TypeScript type checking will be enabled. Be sure to provide the `devSocket` argument above if this is set to `true`. +- **webpack** `function`: A reference to the webpack constructor. ##### `prepareProxy(proxySetting: string, appPublicFolder: string): Object`