UNPKG

@rnx-kit/metro-config

Version:
78 lines (72 loc) 2.51 kB
/** * @typedef {import("metro").AssetData} AssetData; * @typedef {import("metro-config").ConfigT} ConfigT; * @typedef {import("metro-config").Middleware} Middleware; * * @typedef {import("metro/src/Server").default & { * _config?: ConfigT; * }} Server; */ /** * Metro doesn't support assets in a monorepo setup. When the app requests * assets at URLs such as `/assets/../../../node_modules/react-native/<...>`, * the URL will be resolved to `/node_modules/react-native/<...>` and Metro will * fail to resolve them. The workaround is to replace `..` with something else * so the URL doesn't collapse when resolved, then restore them in * `server.enhanceMiddleware`. * * For more details, see https://github.com/facebook/metro/issues/290. * * @param {import("type-fest").Writable<AssetData>} assetData * @returns {AssetData} */ function assetPlugin(assetData) { assetData.httpServerLocation = assetData.httpServerLocation.replaceAll( "../", "@@/" ); return assetData; } /** * Injects {@link assetPlugin} into server asset plugins. * * This should only be called from {@link enhanceMiddleware} to ensure that the * asset plugin is only applied when we are serving. This has the nice * side-effect that the plugin doesn't get included if the middleware is * unused (during bundling) or removed. * * @param {Server} server */ function injectAssetPlugin(server) { const config = server._config; if (!config || !Array.isArray(config.transformer.assetPlugins)) { console.warn( "'@rnx-kit/metro-config' was unable to install the asset plugin for " + "monorepos. Please try again with the latest version. If this " + "warning still persists, you can file an issue at " + "https://github.com/microsoft/rnx-kit/issues/new?assignees=&labels=bug&template=bug_report.yml" ); return; } config.transformer.assetPlugins.push(__filename); } /** * This middleware restores `..` in asset URLs. * * @param {Middleware} middleware * @param {Server} server * @returns {import("connect").NextHandleFunction} */ function enhanceMiddleware(middleware, server) { injectAssetPlugin(server); return (req, res, next) => { const { url } = req; if (url && url.startsWith("/assets/")) { req.url = url.replaceAll("@@/", "../"); } // @ts-ignore Type differs depending on Node version return middleware(req, res, next); }; } module.exports = assetPlugin; module.exports.enhanceMiddleware = enhanceMiddleware;