one 1.17.9 → 1.17.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Root.native.js.map +1 -1
- package/dist/cjs/__mocks__/@react-navigation/native-stack.native.js.map +1 -1
- package/dist/cjs/__mocks__/expo-linking.native.js.map +1 -1
- package/dist/cjs/__mocks__/expo-modules-core.native.js.map +1 -1
- package/dist/cjs/__mocks__/react-native-screens.native.js.map +1 -1
- package/dist/cjs/babel-plugins/environment-guard.native.js.map +1 -1
- package/dist/cjs/babel-plugins/inline-one-server-url.native.js.map +1 -1
- package/dist/cjs/babel-plugins/one-router-metro.native.js.map +1 -1
- package/dist/cjs/babel-plugins/one-router-metro.test.native.js.map +1 -1
- package/dist/cjs/babel-plugins/remove-server-code.native.js.map +1 -1
- package/dist/cjs/babel-preset/index.cjs +7 -2
- package/dist/cjs/babel-preset/index.native.js +7 -2
- package/dist/cjs/babel-preset/index.native.js.map +1 -1
- package/dist/cjs/babel-preset/index.test.cjs +13 -0
- package/dist/cjs/babel-preset/index.test.native.js +13 -0
- package/dist/cjs/babel-preset/index.test.native.js.map +1 -1
- package/dist/cjs/babel-preset/integration.test.native.js.map +1 -1
- package/dist/cjs/cli/build.cjs +14 -11
- package/dist/cjs/cli/build.native.js +14 -11
- package/dist/cjs/cli/build.native.js.map +1 -1
- package/dist/cjs/cli/buildPage.cjs +2 -1
- package/dist/cjs/cli/buildPage.native.js +2 -1
- package/dist/cjs/cli/buildPage.native.js.map +1 -1
- package/dist/cjs/cli/buildPageWorker.native.js.map +1 -1
- package/dist/cjs/cli/checkNodeVersion.native.js.map +1 -1
- package/dist/cjs/cli/daemon.native.js.map +1 -1
- package/dist/cjs/cli/dev.native.js.map +1 -1
- package/dist/cjs/cli/generateBundlerConfig.native.js.map +1 -1
- package/dist/cjs/cli/generateBundlerConfig.test.native.js.map +1 -1
- package/dist/cjs/cli/generateRoutes.native.js.map +1 -1
- package/dist/cjs/cli/generateSitemap.native.js.map +1 -1
- package/dist/cjs/cli/generateSitemap.test.native.js.map +1 -1
- package/dist/cjs/cli/install-error-handlers.native.js.map +1 -1
- package/dist/cjs/cli/label-process.native.js.map +1 -1
- package/dist/cjs/cli/main.native.js.map +1 -1
- package/dist/cjs/cli/patch.native.js.map +1 -1
- package/dist/cjs/cli/patch.test.native.js.map +1 -1
- package/dist/cjs/cli/prebuild.native.js.map +1 -1
- package/dist/cjs/cli/runAndroid.native.js.map +1 -1
- package/dist/cjs/cli/runIos.native.js.map +1 -1
- package/dist/cjs/cli/securityScan.native.js.map +1 -1
- package/dist/cjs/cli/workerPool.native.js.map +1 -1
- package/dist/cjs/cli.native.js.map +1 -1
- package/dist/cjs/clientLoaderResolver.native.js.map +1 -1
- package/dist/cjs/config.native.js.map +1 -1
- package/dist/cjs/constants.cjs +17 -5
- package/dist/cjs/constants.native.js +13 -1
- package/dist/cjs/constants.native.js.map +1 -1
- package/dist/cjs/constants.test.cjs +60 -0
- package/dist/cjs/constants.test.native.js +63 -0
- package/dist/cjs/constants.test.native.js.map +1 -0
- package/dist/cjs/createAPIRoute.native.js.map +1 -1
- package/dist/cjs/createApp.cjs +3 -2
- package/dist/cjs/createHandleRequest.native.js.map +1 -1
- package/dist/cjs/createHandleRequest.test.native.js.map +1 -1
- package/dist/cjs/createMiddleware.native.js.map +1 -1
- package/dist/cjs/daemon/index.native.js.map +1 -1
- package/dist/cjs/daemon/ipc.native.js.map +1 -1
- package/dist/cjs/daemon/picker.native.js.map +1 -1
- package/dist/cjs/daemon/proxy.native.js.map +1 -1
- package/dist/cjs/daemon/registry.native.js.map +1 -1
- package/dist/cjs/daemon/server.cjs +23 -0
- package/dist/cjs/daemon/server.native.js +61 -0
- package/dist/cjs/daemon/server.native.js.map +1 -1
- package/dist/cjs/daemon/tui.native.js.map +1 -1
- package/dist/cjs/daemon/types.native.js.map +1 -1
- package/dist/cjs/daemon/utils.native.js.map +1 -1
- package/dist/cjs/devtools/registry.native.js.map +1 -1
- package/dist/cjs/drawer.native.js.map +1 -1
- package/dist/cjs/fallbackViews/Sitemap.native.js.map +1 -1
- package/dist/cjs/fallbackViews/Unmatched.native.js.map +1 -1
- package/dist/cjs/fork/NavigationContainer.native.js.map +1 -1
- package/dist/cjs/fork/SSRNavigationContainer.native.js.map +1 -1
- package/dist/cjs/fork/__tests__/getPathFromState.test.native.js.map +1 -1
- package/dist/cjs/fork/__tests__/getStateFromPath.test.native.js.map +1 -1
- package/dist/cjs/fork/_shared.native.js.map +1 -1
- package/dist/cjs/fork/createMemoryHistory.native.js.map +1 -1
- package/dist/cjs/fork/createMemoryHistory.test.native.js.map +1 -1
- package/dist/cjs/fork/extractPathFromURL.native.js.map +1 -1
- package/dist/cjs/fork/extractPathFromURL.test.native.js.map +1 -1
- package/dist/cjs/fork/findFocusedRoute.native.js.map +1 -1
- package/dist/cjs/fork/getPathFromState-mods.native.js.map +1 -1
- package/dist/cjs/fork/getPathFromState.native.js.map +1 -1
- package/dist/cjs/fork/getPathFromState.test.native.js.map +1 -1
- package/dist/cjs/fork/getStateFromPath-mods.native.js.map +1 -1
- package/dist/cjs/fork/getStateFromPath.native.js.map +1 -1
- package/dist/cjs/fork/getStateFromPath.test.native.js.map +1 -1
- package/dist/cjs/fork/useThenable.native.js.map +1 -1
- package/dist/cjs/fork/validatePathConfig.native.js.map +1 -1
- package/dist/cjs/getReactNavigationConfig.native.js.map +1 -1
- package/dist/cjs/head/Head.native.js.map +1 -1
- package/dist/cjs/head/HeadModule.native.js.map +1 -1
- package/dist/cjs/head/index.native.js.map +1 -1
- package/dist/cjs/head/types.native.js.map +1 -1
- package/dist/cjs/head/url.native.js.map +1 -1
- package/dist/cjs/headless-server.native.js.map +1 -1
- package/dist/cjs/headless.native.js.map +1 -1
- package/dist/cjs/hooks.native.js.map +1 -1
- package/dist/cjs/hooks.test.native.js.map +1 -1
- package/dist/cjs/href.native.js.map +1 -1
- package/dist/cjs/image/getImageData.native.js.map +1 -1
- package/dist/cjs/image.native.js.map +1 -1
- package/dist/cjs/index.cjs +6 -0
- package/dist/cjs/index.native.js +7 -1
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/interfaces/router.native.js.map +1 -1
- package/dist/cjs/layouts/Drawer.native.js.map +1 -1
- package/dist/cjs/layouts/NativeTabs.native.js.map +1 -1
- package/dist/cjs/layouts/Stack.native.js +1 -1
- package/dist/cjs/layouts/Stack.native.js.map +1 -1
- package/dist/cjs/layouts/Tabs.native.js.map +1 -1
- package/dist/cjs/layouts/stack-utils/StackHeaderBackButton.native.js.map +1 -1
- package/dist/cjs/layouts/stack-utils/StackHeaderComponent.native.js.map +1 -1
- package/dist/cjs/layouts/stack-utils/StackHeaderLeft.native.js.map +1 -1
- package/dist/cjs/layouts/stack-utils/StackHeaderRight.native.js.map +1 -1
- package/dist/cjs/layouts/stack-utils/StackHeaderSearchBar.native.js.map +1 -1
- package/dist/cjs/layouts/stack-utils/StackHeaderTitle.native.js.map +1 -1
- package/dist/cjs/layouts/stack-utils/StackScreen.native.js.map +1 -1
- package/dist/cjs/layouts/stack-utils/__tests__/composition.test.native.js.map +1 -1
- package/dist/cjs/layouts/stack-utils/index.native.js.map +1 -1
- package/dist/cjs/layouts/withLayoutContext.native.js.map +1 -1
- package/dist/cjs/lazyWithRetry.cjs +32 -0
- package/dist/cjs/lazyWithRetry.native.js +37 -0
- package/dist/cjs/lazyWithRetry.native.js.map +1 -0
- package/dist/cjs/link/Link.native.js.map +1 -1
- package/dist/cjs/link/Redirect.native.js.map +1 -1
- package/dist/cjs/link/getLinking.native.js.map +1 -1
- package/dist/cjs/link/href.native.js.map +1 -1
- package/dist/cjs/link/path.native.js.map +1 -1
- package/dist/cjs/link/prefetchIntent.native.js.map +1 -1
- package/dist/cjs/link/prefetchIntent.test.native.js.map +1 -1
- package/dist/cjs/link/prefetchViewport.native.js.map +1 -1
- package/dist/cjs/link/prefetchViewport.test.native.js.map +1 -1
- package/dist/cjs/link/useLinkTo.native.js.map +1 -1
- package/dist/cjs/link/useLoadedNavigation.native.js.map +1 -1
- package/dist/cjs/metro-config/buildOneMetroResolverOverrides.native.js.map +1 -1
- package/dist/cjs/metro-config/getViteMetroPluginOptions.integration.test.native.js.map +1 -1
- package/dist/cjs/metro-config/getViteMetroPluginOptions.native.js +1 -1
- package/dist/cjs/metro-config/getViteMetroPluginOptions.native.js.map +1 -1
- package/dist/cjs/metro-config/withOne.native.js.map +1 -1
- package/dist/cjs/metro-config/withOne.test.native.js.map +1 -1
- package/dist/cjs/native-tabs.native.js.map +1 -1
- package/dist/cjs/notFoundState.native.js.map +1 -1
- package/dist/cjs/polyfills-mobile.native.js.map +1 -1
- package/dist/cjs/polyfills-server.native.js.map +1 -1
- package/dist/cjs/router/FlagsContext.native.js.map +1 -1
- package/dist/cjs/router/Route.native.js.map +1 -1
- package/dist/cjs/router/RouteInfoContext.native.js.map +1 -1
- package/dist/cjs/router/RouterStore.native.js.map +1 -1
- package/dist/cjs/router/SpaShellContext.native.js.map +1 -1
- package/dist/cjs/router/createRoute.native.js.map +1 -1
- package/dist/cjs/router/filterRootHTML.native.js.map +1 -1
- package/dist/cjs/router/findRouteNode.native.js.map +1 -1
- package/dist/cjs/router/getLinkingConfig.native.js.map +1 -1
- package/dist/cjs/router/getLinkingConfig.test.native.js.map +1 -1
- package/dist/cjs/router/getNormalizedStatePath.native.js.map +1 -1
- package/dist/cjs/router/getRouteInfo.native.js.map +1 -1
- package/dist/cjs/router/getRoutes.native.js.map +1 -1
- package/dist/cjs/router/getRoutes.test.native.js.map +1 -1
- package/dist/cjs/router/glob-patterns.native.js.map +1 -1
- package/dist/cjs/router/imperative-api.native.js.map +1 -1
- package/dist/cjs/router/interceptRoutes.native.js.map +1 -1
- package/dist/cjs/router/isIndexPath.native.js.map +1 -1
- package/dist/cjs/router/lastAction.native.js.map +1 -1
- package/dist/cjs/router/linkingConfig.native.js.map +1 -1
- package/dist/cjs/router/matchers.native.js.map +1 -1
- package/dist/cjs/router/matchers.test.native.js.map +1 -1
- package/dist/cjs/router/params.native.js.map +1 -1
- package/dist/cjs/router/router.cjs +22 -7
- package/dist/cjs/router/router.native.js.map +1 -1
- package/dist/cjs/router/serverLocationContext.native.js.map +1 -1
- package/dist/cjs/router/sitemap.native.js.map +1 -1
- package/dist/cjs/router/sitemap.test.native.js.map +1 -1
- package/dist/cjs/router/sortRoutes.native.js.map +1 -1
- package/dist/cjs/router/useInitializeOneRouter.native.js.map +1 -1
- package/dist/cjs/router/useNavigation.native.js.map +1 -1
- package/dist/cjs/router/useScreens.cjs +17 -2
- package/dist/cjs/router/useScreens.native.js +24 -4
- package/dist/cjs/router/useScreens.native.js.map +1 -1
- package/dist/cjs/router/useViteRoutes.native.js.map +1 -1
- package/dist/cjs/router/utils/getNavigateAction.native.js.map +1 -1
- package/dist/cjs/router/utils/getNavigateAction.test.native.js.map +1 -1
- package/dist/cjs/screensFeatureFlags.native.js.map +1 -1
- package/dist/cjs/serve-worker.native.js.map +1 -1
- package/dist/cjs/serve.cjs +2 -1
- package/dist/cjs/serve.native.js +2 -1
- package/dist/cjs/serve.native.js.map +1 -1
- package/dist/cjs/server/ServerContextScript.cjs +4 -3
- package/dist/cjs/server/ServerContextScript.native.js +6 -4
- package/dist/cjs/server/ServerContextScript.native.js.map +1 -1
- package/dist/cjs/server/createRoutesManifest.native.js.map +1 -1
- package/dist/cjs/server/getServerManifest.native.js.map +1 -1
- package/dist/cjs/server/getServerManifest.test.native.js.map +1 -1
- package/dist/cjs/server/oneServe.cjs +21 -8
- package/dist/cjs/server/oneServe.native.js +21 -8
- package/dist/cjs/server/oneServe.native.js.map +1 -1
- package/dist/cjs/server/setServerGlobals.native.js.map +1 -1
- package/dist/cjs/server/setupBuildOptions.cjs +6 -1
- package/dist/cjs/server/setupBuildOptions.native.js +10 -4
- package/dist/cjs/server/setupBuildOptions.native.js.map +1 -1
- package/dist/cjs/server/setupServerGlobals.native.js.map +1 -1
- package/dist/cjs/server/ssrLoaderData.native.js.map +1 -1
- package/dist/cjs/server/staticHtmlFetcher.native.js.map +1 -1
- package/dist/cjs/server/workerHandler.cjs +2 -2
- package/dist/cjs/server/workerHandler.native.js +2 -2
- package/dist/cjs/server/workerHandler.native.js.map +1 -1
- package/dist/cjs/server-render.native.js.map +1 -1
- package/dist/cjs/skewProtection.native.js.map +1 -1
- package/dist/cjs/testing-utils.native.js.map +1 -1
- package/dist/cjs/typed-routes/generateRouteTypes.native.js.map +1 -1
- package/dist/cjs/typed-routes/generateRouteTypes.test.native.js.map +1 -1
- package/dist/cjs/typed-routes/getTypedRoutesDeclarationFile.native.js.map +1 -1
- package/dist/cjs/typed-routes/getTypedRoutesDeclarationFile.test.native.js.map +1 -1
- package/dist/cjs/typed-routes/injectRouteHelpers.native.js.map +1 -1
- package/dist/cjs/types.native.js.map +1 -1
- package/dist/cjs/ui/Slot.native.js.map +1 -1
- package/dist/cjs/ui/TabContext.native.js.map +1 -1
- package/dist/cjs/ui/TabList.native.js.map +1 -1
- package/dist/cjs/ui/TabRouter.native.js.map +1 -1
- package/dist/cjs/ui/TabSlot.native.js.map +1 -1
- package/dist/cjs/ui/TabTrigger.native.js.map +1 -1
- package/dist/cjs/ui/Tabs.native.js.map +1 -1
- package/dist/cjs/ui/common.native.js.map +1 -1
- package/dist/cjs/ui/index.native.js.map +1 -1
- package/dist/cjs/ui/useComponent.native.js.map +1 -1
- package/dist/cjs/useFocusEffect.native.js.map +1 -1
- package/dist/cjs/useLoader.cjs +30 -7
- package/dist/cjs/useLoader.native.js +30 -7
- package/dist/cjs/useLoader.native.js.map +1 -1
- package/dist/cjs/useMatches.native.js.map +1 -1
- package/dist/cjs/useMatches.test.native.js.map +1 -1
- package/dist/cjs/useServerHeadInsertion.native.js.map +1 -1
- package/dist/cjs/utils/assertIsReady.native.js.map +1 -1
- package/dist/cjs/utils/buildOutputPointer.cjs +81 -0
- package/dist/cjs/utils/buildOutputPointer.native.js +92 -0
- package/dist/cjs/utils/buildOutputPointer.native.js.map +1 -0
- package/dist/cjs/utils/buildOutputPointer.test.cjs +94 -0
- package/dist/cjs/utils/buildOutputPointer.test.native.js +97 -0
- package/dist/cjs/utils/buildOutputPointer.test.native.js.map +1 -0
- package/dist/cjs/utils/children.native.js.map +1 -1
- package/dist/cjs/utils/cleanUrl.native.js.map +1 -1
- package/dist/cjs/utils/cleanUrl.test.native.js.map +1 -1
- package/dist/cjs/utils/dynamicImport.cjs +32 -6
- package/dist/cjs/utils/dynamicImport.native.js +35 -2
- package/dist/cjs/utils/dynamicImport.native.js.map +1 -1
- package/dist/cjs/utils/dynamicImport.test.cjs +87 -0
- package/dist/cjs/utils/dynamicImport.test.native.js +108 -0
- package/dist/cjs/utils/dynamicImport.test.native.js.map +1 -0
- package/dist/cjs/utils/ensureExists.native.js.map +1 -1
- package/dist/cjs/utils/evictOldest.native.js.map +1 -1
- package/dist/cjs/utils/existsAsync.native.js.map +1 -1
- package/dist/cjs/utils/findRootLayout.native.js.map +1 -1
- package/dist/cjs/utils/getPageExport.native.js.map +1 -1
- package/dist/cjs/utils/getPathnameFromFilePath.native.js.map +1 -1
- package/dist/cjs/utils/getPathnameFromFilePath.test.native.js.map +1 -1
- package/dist/cjs/utils/getRouterRootFromOneOptions.native.js.map +1 -1
- package/dist/cjs/utils/globDir.native.js.map +1 -1
- package/dist/cjs/utils/hashString.native.js.map +1 -1
- package/dist/cjs/utils/htmlEscape.native.js.map +1 -1
- package/dist/cjs/utils/isResponse.native.js.map +1 -1
- package/dist/cjs/utils/isRolldown.native.js.map +1 -1
- package/dist/cjs/utils/isStatus.native.js.map +1 -1
- package/dist/cjs/utils/pLimit.native.js.map +1 -1
- package/dist/cjs/utils/posixPathContract.test.cjs +66 -0
- package/dist/cjs/utils/posixPathContract.test.native.js +89 -0
- package/dist/cjs/utils/posixPathContract.test.native.js.map +1 -0
- package/dist/cjs/utils/promiseWithResolvers.native.js.map +1 -1
- package/dist/cjs/utils/rand.native.js.map +1 -1
- package/dist/cjs/utils/redirect.native.js.map +1 -1
- package/dist/cjs/utils/removeParams.native.js.map +1 -1
- package/dist/cjs/utils/removeSearch.native.js.map +1 -1
- package/dist/cjs/utils/removeUndefined.native.js.map +1 -1
- package/dist/cjs/utils/routeFileWatch.native.js.map +1 -1
- package/dist/cjs/utils/routeFileWatch.test.native.js.map +1 -1
- package/dist/cjs/utils/style.native.js.map +1 -1
- package/dist/cjs/utils/toAbsolute.native.js.map +1 -1
- package/dist/cjs/utils/toServerOutputPath.cjs +36 -0
- package/dist/cjs/utils/toServerOutputPath.native.js +39 -0
- package/dist/cjs/utils/toServerOutputPath.native.js.map +1 -0
- package/dist/cjs/utils/toServerOutputPath.test.cjs +27 -0
- package/dist/cjs/utils/toServerOutputPath.test.native.js +30 -0
- package/dist/cjs/utils/toServerOutputPath.test.native.js.map +1 -0
- package/dist/cjs/utils/trackLoaderDependencies.native.js.map +1 -1
- package/dist/cjs/utils/url.native.js.map +1 -1
- package/dist/cjs/utils/useConstant.native.js.map +1 -1
- package/dist/cjs/utils/watchFile.native.js.map +1 -1
- package/dist/cjs/utils/weakKey.native.js.map +1 -1
- package/dist/cjs/utils/weakMemo.native.js.map +1 -1
- package/dist/cjs/utils/withStaticProperties.native.js.map +1 -1
- package/dist/cjs/utils/workerImport.native.js.map +1 -1
- package/dist/cjs/validateParams.native.js.map +1 -1
- package/dist/cjs/validateSearch.native.js.map +1 -1
- package/dist/cjs/vercel/build/buildVercelOutputDirectory.native.js.map +1 -1
- package/dist/cjs/vercel/build/config/vc-build-output-config-base.native.js.map +1 -1
- package/dist/cjs/vercel/build/config/vc-config-base.native.js.map +1 -1
- package/dist/cjs/vercel/build/config/vc-package-base.native.js.map +1 -1
- package/dist/cjs/vercel/build/generate/createApiServerlessFunction.native.js.map +1 -1
- package/dist/cjs/vercel/build/generate/createSsrServerlessFunction.native.js.map +1 -1
- package/dist/cjs/vercel/build/getPathFromRoute.native.js.map +1 -1
- package/dist/cjs/views/EmptyRoute.native.js.map +1 -1
- package/dist/cjs/views/ErrorBoundary.native.js.map +1 -1
- package/dist/cjs/views/LoadProgressBar.native.js.map +1 -1
- package/dist/cjs/views/Navigator.native.js.map +1 -1
- package/dist/cjs/views/OneStackRouter.native.js.map +1 -1
- package/dist/cjs/views/Protected.native.js.map +1 -1
- package/dist/cjs/views/RootErrorBoundary.native.js.map +1 -1
- package/dist/cjs/views/Screen.native.js.map +1 -1
- package/dist/cjs/views/ScrollBehavior.native.js.map +1 -1
- package/dist/cjs/views/SourceInspector.native.js.map +1 -1
- package/dist/cjs/views/Try.native.js.map +1 -1
- package/dist/cjs/vite/DevHead.native.js.map +1 -1
- package/dist/cjs/vite/constants.native.js.map +1 -1
- package/dist/cjs/vite/customNodeExternals.native.js.map +1 -1
- package/dist/cjs/vite/ensureTsConfig.native.js.map +1 -1
- package/dist/cjs/vite/findDepsToOptimize.native.js.map +1 -1
- package/dist/cjs/vite/getManifest.native.js.map +1 -1
- package/dist/cjs/vite/getManifest.test.cjs +46 -0
- package/dist/cjs/vite/getManifest.test.native.js +52 -0
- package/dist/cjs/vite/getManifest.test.native.js.map +1 -0
- package/dist/cjs/vite/loadConfig.native.js.map +1 -1
- package/dist/cjs/vite/makePluginWebOnly.native.js.map +1 -1
- package/dist/cjs/vite/one-server-only.test.native.js.map +1 -1
- package/dist/cjs/vite/one.cjs +4 -3
- package/dist/cjs/vite/one.native.js +4 -3
- package/dist/cjs/vite/one.native.js.map +1 -1
- package/dist/cjs/vite/plugins/SSRCSSPlugin.native.js.map +1 -1
- package/dist/cjs/vite/plugins/clientTreeShakePlugin.native.js.map +1 -1
- package/dist/cjs/vite/plugins/clientTreeShakePlugin.test.native.js.map +1 -1
- package/dist/cjs/vite/plugins/criticalCSSPlugin.native.js.map +1 -1
- package/dist/cjs/vite/plugins/criticalCSSPlugin.test.native.js.map +1 -1
- package/dist/cjs/vite/plugins/devtoolsPlugin.native.js.map +1 -1
- package/dist/cjs/vite/plugins/environmentGuardPlugin.native.js.map +1 -1
- package/dist/cjs/vite/plugins/environmentGuardPlugin.test.native.js.map +1 -1
- package/dist/cjs/vite/plugins/fileSystemRouterPlugin.cjs +25 -16
- package/dist/cjs/vite/plugins/fileSystemRouterPlugin.native.js +25 -16
- package/dist/cjs/vite/plugins/fileSystemRouterPlugin.native.js.map +1 -1
- package/dist/cjs/vite/plugins/fileSystemRouterPlugin.test.native.js.map +1 -1
- package/dist/cjs/vite/plugins/fixDependenciesPlugin.native.js.map +1 -1
- package/dist/cjs/vite/plugins/generateFileSystemRouteTypesPlugin.native.js.map +1 -1
- package/dist/cjs/vite/plugins/imageDataPlugin.native.js.map +1 -1
- package/dist/cjs/vite/plugins/imageDataPlugin.test.native.js.map +1 -1
- package/dist/cjs/vite/plugins/removeReactNativeWebAnimatedPlugin.native.js.map +1 -1
- package/dist/cjs/vite/plugins/sourceInspectorPlugin.cjs +1 -1
- package/dist/cjs/vite/plugins/sourceInspectorPlugin.native.js +1 -1
- package/dist/cjs/vite/plugins/sourceInspectorPlugin.native.js.map +1 -1
- package/dist/cjs/vite/plugins/sourceInspectorPlugin.test.native.js.map +1 -1
- package/dist/cjs/vite/plugins/useDomPlugin.native.js.map +1 -1
- package/dist/cjs/vite/plugins/virtualEntryConstants.native.js.map +1 -1
- package/dist/cjs/vite/plugins/virtualEntryPlugin.cjs +2 -1
- package/dist/cjs/vite/plugins/virtualEntryPlugin.native.js +2 -1
- package/dist/cjs/vite/plugins/virtualEntryPlugin.native.js.map +1 -1
- package/dist/cjs/vite/plugins/virtualEntryPlugin.test.native.js.map +1 -1
- package/dist/cjs/vite/plugins/warmRoutesPlugin.native.js.map +1 -1
- package/dist/cjs/vite/replaceLoader.native.js.map +1 -1
- package/dist/cjs/vite/resolveResponse.native.js.map +1 -1
- package/dist/cjs/vite/types.native.js.map +1 -1
- package/dist/cjs/vite-auto-warm.native.js.map +1 -1
- package/dist/cjs/vite.native.js.map +1 -1
- package/dist/cjs/zero/getQueryKey.native.js.map +1 -1
- package/dist/cjs/zero/isZeroQuery.native.js.map +1 -1
- package/dist/cjs/zero/resolveQuery.native.js.map +1 -1
- package/dist/cjs/zero/subscribeToQuery.native.js.map +1 -1
- package/dist/cjs/zero/types.native.js.map +1 -1
- package/dist/cjs/zero/useQuery.native.js.map +1 -1
- package/dist/cjs/zero/useQueryZero.native.js.map +1 -1
- package/dist/cjs/zero.native.js.map +1 -1
- package/dist/esm/babel-preset/index.mjs +7 -2
- package/dist/esm/babel-preset/index.mjs.map +1 -1
- package/dist/esm/babel-preset/index.native.js +7 -2
- package/dist/esm/babel-preset/index.native.js.map +1 -1
- package/dist/esm/babel-preset/index.test.mjs +13 -0
- package/dist/esm/babel-preset/index.test.mjs.map +1 -1
- package/dist/esm/babel-preset/index.test.native.js +13 -0
- package/dist/esm/babel-preset/index.test.native.js.map +1 -1
- package/dist/esm/cli/build.mjs +15 -12
- package/dist/esm/cli/build.mjs.map +1 -1
- package/dist/esm/cli/build.native.js +15 -12
- package/dist/esm/cli/build.native.js.map +1 -1
- package/dist/esm/cli/buildPage.mjs +2 -1
- package/dist/esm/cli/buildPage.mjs.map +1 -1
- package/dist/esm/cli/buildPage.native.js +2 -1
- package/dist/esm/cli/buildPage.native.js.map +1 -1
- package/dist/esm/constants.mjs +14 -5
- package/dist/esm/constants.mjs.map +1 -1
- package/dist/esm/constants.native.js +10 -1
- package/dist/esm/constants.native.js.map +1 -1
- package/dist/esm/constants.test.mjs +37 -0
- package/dist/esm/constants.test.mjs.map +1 -0
- package/dist/esm/constants.test.native.js +37 -0
- package/dist/esm/constants.test.native.js.map +1 -0
- package/dist/esm/createApp.mjs +3 -2
- package/dist/esm/createApp.mjs.map +1 -1
- package/dist/esm/daemon/server.mjs +23 -0
- package/dist/esm/daemon/server.mjs.map +1 -1
- package/dist/esm/daemon/server.native.js +61 -0
- package/dist/esm/daemon/server.native.js.map +1 -1
- package/dist/esm/index.js +3 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.mjs +3 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +3 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/lazyWithRetry.mjs +7 -0
- package/dist/esm/lazyWithRetry.mjs.map +1 -0
- package/dist/esm/lazyWithRetry.native.js +9 -0
- package/dist/esm/lazyWithRetry.native.js.map +1 -0
- package/dist/esm/router/router.mjs +22 -7
- package/dist/esm/router/router.mjs.map +1 -1
- package/dist/esm/router/router.native.js.map +1 -1
- package/dist/esm/router/useScreens.mjs +18 -3
- package/dist/esm/router/useScreens.mjs.map +1 -1
- package/dist/esm/router/useScreens.native.js +25 -5
- package/dist/esm/router/useScreens.native.js.map +1 -1
- package/dist/esm/serve.mjs +2 -1
- package/dist/esm/serve.mjs.map +1 -1
- package/dist/esm/serve.native.js +2 -1
- package/dist/esm/serve.native.js.map +1 -1
- package/dist/esm/server/ServerContextScript.mjs +4 -3
- package/dist/esm/server/ServerContextScript.mjs.map +1 -1
- package/dist/esm/server/ServerContextScript.native.js +6 -4
- package/dist/esm/server/ServerContextScript.native.js.map +1 -1
- package/dist/esm/server/oneServe.mjs +23 -10
- package/dist/esm/server/oneServe.mjs.map +1 -1
- package/dist/esm/server/oneServe.native.js +23 -10
- package/dist/esm/server/oneServe.native.js.map +1 -1
- package/dist/esm/server/setupBuildOptions.mjs +6 -1
- package/dist/esm/server/setupBuildOptions.mjs.map +1 -1
- package/dist/esm/server/setupBuildOptions.native.js +10 -4
- package/dist/esm/server/setupBuildOptions.native.js.map +1 -1
- package/dist/esm/server/workerHandler.mjs +3 -3
- package/dist/esm/server/workerHandler.mjs.map +1 -1
- package/dist/esm/server/workerHandler.native.js +3 -3
- package/dist/esm/server/workerHandler.native.js.map +1 -1
- package/dist/esm/useLoader.mjs +30 -7
- package/dist/esm/useLoader.mjs.map +1 -1
- package/dist/esm/useLoader.native.js +30 -7
- package/dist/esm/useLoader.native.js.map +1 -1
- package/dist/esm/utils/buildOutputPointer.mjs +43 -0
- package/dist/esm/utils/buildOutputPointer.mjs.map +1 -0
- package/dist/esm/utils/buildOutputPointer.native.js +51 -0
- package/dist/esm/utils/buildOutputPointer.native.js.map +1 -0
- package/dist/esm/utils/buildOutputPointer.test.mjs +71 -0
- package/dist/esm/utils/buildOutputPointer.test.mjs.map +1 -0
- package/dist/esm/utils/buildOutputPointer.test.native.js +71 -0
- package/dist/esm/utils/buildOutputPointer.test.native.js.map +1 -0
- package/dist/esm/utils/dynamicImport.mjs +29 -6
- package/dist/esm/utils/dynamicImport.mjs.map +1 -1
- package/dist/esm/utils/dynamicImport.native.js +32 -2
- package/dist/esm/utils/dynamicImport.native.js.map +1 -1
- package/dist/esm/utils/dynamicImport.test.mjs +88 -0
- package/dist/esm/utils/dynamicImport.test.mjs.map +1 -0
- package/dist/esm/utils/dynamicImport.test.native.js +106 -0
- package/dist/esm/utils/dynamicImport.test.native.js.map +1 -0
- package/dist/esm/utils/posixPathContract.test.mjs +67 -0
- package/dist/esm/utils/posixPathContract.test.mjs.map +1 -0
- package/dist/esm/utils/posixPathContract.test.native.js +87 -0
- package/dist/esm/utils/posixPathContract.test.native.js.map +1 -0
- package/dist/esm/utils/toServerOutputPath.mjs +11 -0
- package/dist/esm/utils/toServerOutputPath.mjs.map +1 -0
- package/dist/esm/utils/toServerOutputPath.native.js +11 -0
- package/dist/esm/utils/toServerOutputPath.native.js.map +1 -0
- package/dist/esm/utils/toServerOutputPath.test.mjs +28 -0
- package/dist/esm/utils/toServerOutputPath.test.mjs.map +1 -0
- package/dist/esm/utils/toServerOutputPath.test.native.js +28 -0
- package/dist/esm/utils/toServerOutputPath.test.native.js.map +1 -0
- package/dist/esm/vite/getManifest.test.mjs +47 -0
- package/dist/esm/vite/getManifest.test.mjs.map +1 -0
- package/dist/esm/vite/getManifest.test.native.js +50 -0
- package/dist/esm/vite/getManifest.test.native.js.map +1 -0
- package/dist/esm/vite/one.mjs +4 -3
- package/dist/esm/vite/one.mjs.map +1 -1
- package/dist/esm/vite/one.native.js +4 -3
- package/dist/esm/vite/one.native.js.map +1 -1
- package/dist/esm/vite/plugins/fileSystemRouterPlugin.mjs +26 -17
- package/dist/esm/vite/plugins/fileSystemRouterPlugin.mjs.map +1 -1
- package/dist/esm/vite/plugins/fileSystemRouterPlugin.native.js +26 -17
- package/dist/esm/vite/plugins/fileSystemRouterPlugin.native.js.map +1 -1
- package/dist/esm/vite/plugins/sourceInspectorPlugin.mjs +1 -1
- package/dist/esm/vite/plugins/sourceInspectorPlugin.mjs.map +1 -1
- package/dist/esm/vite/plugins/sourceInspectorPlugin.native.js +1 -1
- package/dist/esm/vite/plugins/sourceInspectorPlugin.native.js.map +1 -1
- package/dist/esm/vite/plugins/virtualEntryPlugin.mjs +2 -1
- package/dist/esm/vite/plugins/virtualEntryPlugin.mjs.map +1 -1
- package/dist/esm/vite/plugins/virtualEntryPlugin.native.js +2 -1
- package/dist/esm/vite/plugins/virtualEntryPlugin.native.js.map +1 -1
- package/package.json +23 -9
- package/src/babel-preset/index.test.ts +20 -0
- package/src/babel-preset/index.ts +21 -4
- package/src/cli/build.ts +23 -15
- package/src/cli/buildPage.ts +3 -1
- package/src/constants.test.ts +55 -0
- package/src/constants.ts +32 -4
- package/src/createApp.tsx +7 -2
- package/src/daemon/server.ts +30 -0
- package/src/index.ts +9 -0
- package/src/lazyWithRetry.tsx +21 -0
- package/src/router/router.ts +32 -7
- package/src/router/useScreens.tsx +22 -3
- package/src/serve.ts +2 -2
- package/src/server/ServerContextScript.tsx +9 -3
- package/src/server/oneServe.ts +33 -15
- package/src/server/setupBuildOptions.ts +11 -2
- package/src/server/workerHandler.ts +9 -5
- package/src/useLoader.ts +41 -6
- package/src/utils/buildOutputPointer.test.ts +97 -0
- package/src/utils/buildOutputPointer.ts +71 -0
- package/src/utils/dynamicImport.test.ts +92 -0
- package/src/utils/dynamicImport.ts +80 -13
- package/src/utils/posixPathContract.test.ts +97 -0
- package/src/utils/toServerOutputPath.test.ts +49 -0
- package/src/utils/toServerOutputPath.ts +11 -0
- package/src/vite/getManifest.test.ts +49 -0
- package/src/vite/one.ts +9 -5
- package/src/vite/plugins/fileSystemRouterPlugin.tsx +31 -17
- package/src/vite/plugins/sourceInspectorPlugin.ts +2 -1
- package/src/vite/plugins/virtualEntryPlugin.ts +5 -2
- package/types/babel-preset/index.d.ts.map +1 -1
- package/types/cli/build.d.ts.map +1 -1
- package/types/cli/buildPage.d.ts.map +1 -1
- package/types/constants.d.ts +7 -4
- package/types/constants.d.ts.map +1 -1
- package/types/constants.test.d.ts +2 -0
- package/types/constants.test.d.ts.map +1 -0
- package/types/createApp.d.ts.map +1 -1
- package/types/daemon/server.d.ts.map +1 -1
- package/types/index.d.ts +2 -0
- package/types/index.d.ts.map +1 -1
- package/types/lazyWithRetry.d.ts +6 -0
- package/types/lazyWithRetry.d.ts.map +1 -0
- package/types/router/router.d.ts.map +1 -1
- package/types/router/useScreens.d.ts.map +1 -1
- package/types/serve.d.ts.map +1 -1
- package/types/server/ServerContextScript.d.ts.map +1 -1
- package/types/server/oneServe.d.ts.map +1 -1
- package/types/server/setupBuildOptions.d.ts.map +1 -1
- package/types/server/workerHandler.d.ts.map +1 -1
- package/types/useLoader.d.ts.map +1 -1
- package/types/utils/buildOutputPointer.d.ts +4 -0
- package/types/utils/buildOutputPointer.d.ts.map +1 -0
- package/types/utils/buildOutputPointer.test.d.ts +2 -0
- package/types/utils/buildOutputPointer.test.d.ts.map +1 -0
- package/types/utils/dynamicImport.d.ts +10 -2
- package/types/utils/dynamicImport.d.ts.map +1 -1
- package/types/utils/dynamicImport.test.d.ts +2 -0
- package/types/utils/dynamicImport.test.d.ts.map +1 -0
- package/types/utils/posixPathContract.test.d.ts +2 -0
- package/types/utils/posixPathContract.test.d.ts.map +1 -0
- package/types/utils/toServerOutputPath.d.ts +2 -0
- package/types/utils/toServerOutputPath.d.ts.map +1 -0
- package/types/utils/toServerOutputPath.test.d.ts +2 -0
- package/types/utils/toServerOutputPath.test.d.ts.map +1 -0
- package/types/vite/getManifest.test.d.ts +2 -0
- package/types/vite/getManifest.test.d.ts.map +1 -0
- package/types/vite/one.d.ts.map +1 -1
- package/types/vite/plugins/fileSystemRouterPlugin.d.ts.map +1 -1
- package/types/vite/plugins/sourceInspectorPlugin.d.ts.map +1 -1
- package/types/vite/plugins/virtualEntryPlugin.d.ts.map +1 -1
package/src/serve.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { VXRNOptions } from 'vxrn'
|
|
|
6
6
|
import { setServerGlobals } from './server/setServerGlobals'
|
|
7
7
|
import { setupBuildInfo } from './server/setupBuildOptions'
|
|
8
8
|
import { ensureExists } from './utils/ensureExists'
|
|
9
|
+
import { resolveServeOutDir } from './utils/buildOutputPointer'
|
|
9
10
|
import type { One } from './vite/types'
|
|
10
11
|
|
|
11
12
|
// formatErrorSafely + the prepareStackTrace guard prevent a buggy transitive
|
|
@@ -191,8 +192,7 @@ async function serveWithCluster(args: Parameters<typeof serve>[0], numWorkers: n
|
|
|
191
192
|
}
|
|
192
193
|
|
|
193
194
|
async function startWorker(args: Parameters<typeof serve>[0]) {
|
|
194
|
-
const outDir =
|
|
195
|
-
args?.outDir || (FSExtra.existsSync('buildInfo.json') ? '.' : null) || 'dist'
|
|
195
|
+
const outDir = await resolveServeOutDir(args?.outDir)
|
|
196
196
|
const buildInfo = (await FSExtra.readJSON(`${outDir}/buildInfo.json`)) as One.BuildInfo
|
|
197
197
|
const { oneOptions } = buildInfo
|
|
198
198
|
|
|
@@ -25,12 +25,18 @@ export function ServerContextScript() {
|
|
|
25
25
|
// strip cssContents - read from DOM instead (CSSPrehydrateScript)
|
|
26
26
|
const { cssContents, ...restContext } = context || {}
|
|
27
27
|
|
|
28
|
-
// strip page loaderData from matches to avoid double-serialization
|
|
29
|
-
|
|
28
|
+
// strip page loaderData from matches to avoid double-serialization.
|
|
29
|
+
// we always strip the leaf (its data lives in restContext.loaderData and
|
|
30
|
+
// gets restored client-side onto matches[last]). reference equality on
|
|
31
|
+
// restContext.loaderData was too aggressive — if a layout's loaderData
|
|
32
|
+
// happened to ref-equal the page's (e.g. both `null`), the layout would
|
|
33
|
+
// permanently lose its data after hydration.
|
|
34
|
+
const lastMatchIndex = (restContext.matches?.length ?? 0) - 1
|
|
35
|
+
const compactMatches = restContext.matches?.map((m: any, i: number) => ({
|
|
30
36
|
routeId: m.routeId,
|
|
31
37
|
pathname: m.pathname,
|
|
32
38
|
params: m.params,
|
|
33
|
-
...(
|
|
39
|
+
...(i === lastMatchIndex ? {} : { loaderData: m.loaderData }),
|
|
34
40
|
}))
|
|
35
41
|
|
|
36
42
|
const clientContext = {
|
package/src/server/oneServe.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Hono, MiddlewareHandler } from 'hono'
|
|
2
2
|
import type { BlankEnv } from 'hono/types'
|
|
3
3
|
import { readFile } from 'node:fs/promises'
|
|
4
|
-
import { join } from 'node:path'
|
|
4
|
+
import { join, posix } from 'node:path'
|
|
5
5
|
import {
|
|
6
|
-
|
|
6
|
+
CSS_PRELOAD_JS_POSTFIX_REGEX,
|
|
7
7
|
LOADER_JS_POSTFIX_UNCACHED,
|
|
8
|
-
|
|
8
|
+
PRELOAD_JS_POSTFIX_REGEX,
|
|
9
9
|
} from '../constants'
|
|
10
10
|
import {
|
|
11
11
|
compileManifest,
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import type { RenderAppProps } from '../types'
|
|
18
18
|
import { getPathFromLoaderPath } from '../utils/cleanUrl'
|
|
19
19
|
import { toAbsoluteUrl } from '../utils/toAbsolute'
|
|
20
|
+
import { toServerOutputPath } from '../utils/toServerOutputPath'
|
|
20
21
|
import type { One } from '../vite/types'
|
|
21
22
|
import type { RouteInfoCompiled } from './createRoutesManifest'
|
|
22
23
|
import { setSSRLoaderData } from './ssrLoaderData'
|
|
@@ -24,6 +25,22 @@ import { getFetchStaticHtml } from './staticHtmlFetcher'
|
|
|
24
25
|
|
|
25
26
|
const debugRouter = process.env.ONE_DEBUG_ROUTER
|
|
26
27
|
|
|
28
|
+
// Bounded map helper: prevents unbounded memory growth by evicting the oldest
|
|
29
|
+
// entry when the map exceeds the specified maximum size. Uses insertion order
|
|
30
|
+
// (Map preserves insertion order) — the first-inserted entry is evicted first.
|
|
31
|
+
const MODULE_CACHE_MAX = 500
|
|
32
|
+
function setBounded<K, V>(map: Map<K, V>, key: K, value: V, max: number): void {
|
|
33
|
+
if (map.has(key)) {
|
|
34
|
+
map.set(key, value)
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
if (map.size >= max) {
|
|
38
|
+
const firstKey = map.keys().next().value
|
|
39
|
+
if (firstKey !== undefined) map.delete(firstKey as K)
|
|
40
|
+
}
|
|
41
|
+
map.set(key, value)
|
|
42
|
+
}
|
|
43
|
+
|
|
27
44
|
// forwards response headers to a hono context, preserving individual
|
|
28
45
|
// set-cookie values (Headers.forEach joins them into one unparseable string)
|
|
29
46
|
function forwardHeaders(response: Response, context: { header: Function }) {
|
|
@@ -164,9 +181,7 @@ export async function oneServe(
|
|
|
164
181
|
// cold path - async import
|
|
165
182
|
return (async () => {
|
|
166
183
|
const pathToResolve = serverPath || lazyKey || ''
|
|
167
|
-
const resolvedPath = pathToResolve
|
|
168
|
-
? pathToResolve
|
|
169
|
-
: join('./', `${outDir}/server`, pathToResolve)
|
|
184
|
+
const resolvedPath = toServerOutputPath(pathToResolve, outDir)
|
|
170
185
|
|
|
171
186
|
let routeExported: any
|
|
172
187
|
if (moduleImportCache.has(cacheKey)) {
|
|
@@ -177,14 +192,14 @@ export async function oneServe(
|
|
|
177
192
|
? await options.lazyRoutes.pages[lazyKey]()
|
|
178
193
|
: await import(toAbsoluteUrl(resolvedPath))
|
|
179
194
|
: await import(toAbsoluteUrl(serverPath!))
|
|
180
|
-
moduleImportCache
|
|
195
|
+
setBounded(moduleImportCache, cacheKey, routeExported, MODULE_CACHE_MAX)
|
|
181
196
|
}
|
|
182
197
|
|
|
183
198
|
const loader = routeExported?.loader || null
|
|
184
|
-
loaderCache
|
|
199
|
+
setBounded(loaderCache, cacheKey, loader, MODULE_CACHE_MAX)
|
|
185
200
|
// also cache loaderCache export for coalescing
|
|
186
201
|
const loaderCacheFn = routeExported?.loaderCache ?? null
|
|
187
|
-
loaderCacheFnMap
|
|
202
|
+
setBounded(loaderCacheFnMap, cacheKey, loaderCacheFn, MODULE_CACHE_MAX)
|
|
188
203
|
return loader
|
|
189
204
|
})()
|
|
190
205
|
}
|
|
@@ -314,7 +329,8 @@ export async function oneServe(
|
|
|
314
329
|
}
|
|
315
330
|
// both vite and rolldown-vite replace brackets with underscores in output filenames
|
|
316
331
|
const fileName = route.page.slice(1).replace(/\[/g, '_').replace(/\]/g, '_')
|
|
317
|
-
|
|
332
|
+
// posix matches the serverJsPath/builtMiddlewares producer convention
|
|
333
|
+
const apiFile = posix.join(outDir, 'api', fileName + (apiCJS ? '.cjs' : '.js'))
|
|
318
334
|
return await import(toAbsoluteUrl(apiFile))
|
|
319
335
|
},
|
|
320
336
|
|
|
@@ -328,9 +344,7 @@ export async function oneServe(
|
|
|
328
344
|
|
|
329
345
|
async handleLoader({ route, loaderProps }) {
|
|
330
346
|
const routeFile = (route as any).routeFile || route.file
|
|
331
|
-
const serverPath = route.file
|
|
332
|
-
? route.file
|
|
333
|
-
: join('./', `${outDir}/server`, route.file)
|
|
347
|
+
const serverPath = toServerOutputPath(route.file, outDir)
|
|
334
348
|
|
|
335
349
|
let loader: Function | null
|
|
336
350
|
try {
|
|
@@ -940,7 +954,11 @@ url: ${url}`)
|
|
|
940
954
|
|
|
941
955
|
// TODO make this inside each page, need to make loader urls just be REGULAR_URL + loaderpostfix
|
|
942
956
|
app.get('*', async (c, next) => {
|
|
943
|
-
|
|
957
|
+
// regex match (not exact CACHE_KEY suffix) — see constants.ts:
|
|
958
|
+
// PRELOAD_JS_POSTFIX_REGEX. handles dynamic segments and the rare
|
|
959
|
+
// CACHE_KEY-drift case by funnelling misses through the graceful
|
|
960
|
+
// empty-200 below instead of the static-handler 404.
|
|
961
|
+
if (PRELOAD_JS_POSTFIX_REGEX.test(c.req.path)) {
|
|
944
962
|
// TODO handle dynamic segments (i think the below loader has some logic for this)
|
|
945
963
|
if (!preloads[c.req.path]) {
|
|
946
964
|
// no preload exists 200 gracefully
|
|
@@ -950,7 +968,7 @@ url: ${url}`)
|
|
|
950
968
|
}
|
|
951
969
|
}
|
|
952
970
|
|
|
953
|
-
if (c.req.path
|
|
971
|
+
if (CSS_PRELOAD_JS_POSTFIX_REGEX.test(c.req.path)) {
|
|
954
972
|
// Return empty resolved promise if no CSS preload exists for this route
|
|
955
973
|
if (!cssPreloads?.[c.req.path]) {
|
|
956
974
|
c.header('Content-Type', 'text/javascript')
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
+
import { setCacheKey } from '../constants'
|
|
1
2
|
import type { One } from '../vite/types'
|
|
2
3
|
|
|
3
4
|
export function setupBuildInfo(buildInfo: One.BuildInfo) {
|
|
4
|
-
// ensure cache key matches build
|
|
5
|
-
process
|
|
5
|
+
// ensure cache key matches build. env var is for child workers spawned later;
|
|
6
|
+
// setCacheKey rebinds the in-memory postfixes for the current process so any
|
|
7
|
+
// code that imported constants before setupBuildInfo ran (e.g. workerHandler
|
|
8
|
+
// pulled in by serve-worker's static import graph) sees the pinned value.
|
|
9
|
+
// headless-server may not pass `constants` — skip gracefully.
|
|
10
|
+
const key = buildInfo.constants?.CACHE_KEY
|
|
11
|
+
if (key) {
|
|
12
|
+
process.env.ONE_CACHE_KEY ||= key
|
|
13
|
+
setCacheKey(key)
|
|
14
|
+
}
|
|
6
15
|
process.env.ONE_DEFAULT_RENDER_MODE ||=
|
|
7
16
|
buildInfo.oneOptions?.web?.defaultRenderMode || 'ssg'
|
|
8
17
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
CSS_PRELOAD_JS_POSTFIX_REGEX,
|
|
3
3
|
LOADER_JS_POSTFIX_UNCACHED,
|
|
4
|
-
|
|
4
|
+
PRELOAD_JS_POSTFIX_REGEX,
|
|
5
5
|
} from '../constants'
|
|
6
6
|
import {
|
|
7
7
|
compileManifest,
|
|
@@ -597,8 +597,12 @@ export function createWorkerHandler(options: WorkerHandlerOptions) {
|
|
|
597
597
|
}
|
|
598
598
|
}
|
|
599
599
|
|
|
600
|
-
// 2. preload endpoints (empty response if no preload exists)
|
|
601
|
-
|
|
600
|
+
// 2. preload endpoints (empty response if no preload exists).
|
|
601
|
+
// regex match (not exact CACHE_KEY suffix) — see constants.ts:
|
|
602
|
+
// PRELOAD_JS_POSTFIX_REGEX. handles dynamic segments and the rare
|
|
603
|
+
// CACHE_KEY-drift case by funnelling misses through the graceful
|
|
604
|
+
// empty-200 below instead of the static-handler 404.
|
|
605
|
+
if (PRELOAD_JS_POSTFIX_REGEX.test(pathname)) {
|
|
602
606
|
if (!currentPreloads[pathname]) {
|
|
603
607
|
return new Response('', {
|
|
604
608
|
headers: { 'Content-Type': 'text/javascript' },
|
|
@@ -608,7 +612,7 @@ export function createWorkerHandler(options: WorkerHandlerOptions) {
|
|
|
608
612
|
return null
|
|
609
613
|
}
|
|
610
614
|
|
|
611
|
-
if (
|
|
615
|
+
if (CSS_PRELOAD_JS_POSTFIX_REGEX.test(pathname)) {
|
|
612
616
|
if (!currentCssPreloads?.[pathname]) {
|
|
613
617
|
return new Response('export default Promise.resolve()', {
|
|
614
618
|
headers: { 'Content-Type': 'text/javascript' },
|
package/src/useLoader.ts
CHANGED
|
@@ -90,8 +90,26 @@ registerDevtoolsFunction('recordLoaderTiming', recordLoaderTiming)
|
|
|
90
90
|
const loaderState: Record<string, LoaderStateEntry> = {}
|
|
91
91
|
const subscribers = new Set<() => void>()
|
|
92
92
|
|
|
93
|
+
// Prevent unbounded growth of loaderState by pruning the oldest entry when
|
|
94
|
+
// we exceed this limit. Most apps navigate a limited set of routes, but
|
|
95
|
+
// dynamic params (e.g. /users/:id) can generate thousands of unique keys.
|
|
96
|
+
const LOADER_STATE_MAX = 200
|
|
97
|
+
const loaderStateKeys: string[] = []
|
|
98
|
+
|
|
99
|
+
function setBoundedLoaderState(path: string, entry: LoaderStateEntry) {
|
|
100
|
+
if (!(path in loaderState)) {
|
|
101
|
+
loaderStateKeys.push(path)
|
|
102
|
+
if (loaderStateKeys.length > LOADER_STATE_MAX) {
|
|
103
|
+
const oldest = loaderStateKeys.shift()!
|
|
104
|
+
delete loaderState[oldest]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
loaderState[path] = entry
|
|
108
|
+
}
|
|
109
|
+
|
|
93
110
|
function updateState(path: string, updates: Partial<LoaderStateEntry>) {
|
|
94
|
-
|
|
111
|
+
const merged = { ...loaderState[path], ...updates }
|
|
112
|
+
setBoundedLoaderState(path, merged)
|
|
95
113
|
subscribers.forEach((callback) => {
|
|
96
114
|
callback()
|
|
97
115
|
})
|
|
@@ -103,14 +121,15 @@ function subscribe(callback: () => void) {
|
|
|
103
121
|
}
|
|
104
122
|
|
|
105
123
|
function getLoaderState(path: string, preloadedData?: any): LoaderStateEntry {
|
|
106
|
-
if (!loaderState
|
|
107
|
-
|
|
124
|
+
if (!(path in loaderState)) {
|
|
125
|
+
const entry: LoaderStateEntry = {
|
|
108
126
|
data: preloadedData,
|
|
109
127
|
error: undefined,
|
|
110
128
|
promise: undefined,
|
|
111
129
|
state: 'idle',
|
|
112
130
|
hasLoadedOnce: !!preloadedData,
|
|
113
131
|
}
|
|
132
|
+
setBoundedLoaderState(path, entry)
|
|
114
133
|
}
|
|
115
134
|
return loaderState[path]
|
|
116
135
|
}
|
|
@@ -759,6 +778,22 @@ export function useLoader<
|
|
|
759
778
|
const results = new Map()
|
|
760
779
|
const started = new Map()
|
|
761
780
|
|
|
781
|
+
// Prevent unbounded growth of useAsyncFn caches. Under sustained client-side
|
|
782
|
+
// navigation with many unique param combinations, these can accumulate large
|
|
783
|
+
// API responses. 100 entries is generous for typical route counts.
|
|
784
|
+
const USE_ASYNC_FN_CACHE_MAX = 100
|
|
785
|
+
|
|
786
|
+
function setBoundedResults(key: string, value: any) {
|
|
787
|
+
if (results.size >= USE_ASYNC_FN_CACHE_MAX && !results.has(key)) {
|
|
788
|
+
const firstKey = results.keys().next().value
|
|
789
|
+
if (firstKey !== undefined) {
|
|
790
|
+
results.delete(firstKey as string)
|
|
791
|
+
started.delete(firstKey as string)
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
results.set(key, value)
|
|
795
|
+
}
|
|
796
|
+
|
|
762
797
|
// maps loader function → its route's loaderData for SSR
|
|
763
798
|
// populated before render in oneServe.ts, cleared after
|
|
764
799
|
// re-export for backwards compat
|
|
@@ -780,14 +815,14 @@ function useAsyncFn(val: any, props?: any) {
|
|
|
780
815
|
if (next instanceof Promise) {
|
|
781
816
|
next = next
|
|
782
817
|
.then((final) => {
|
|
783
|
-
|
|
818
|
+
setBoundedResults(key, final)
|
|
784
819
|
})
|
|
785
820
|
.catch((err) => {
|
|
786
821
|
console.error(`Error running loader()`, err)
|
|
787
|
-
|
|
822
|
+
setBoundedResults(key, undefined)
|
|
788
823
|
})
|
|
789
824
|
}
|
|
790
|
-
|
|
825
|
+
setBoundedResults(key, next)
|
|
791
826
|
}
|
|
792
827
|
}
|
|
793
828
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { mkdtempSync } from 'node:fs'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import FSExtra from 'fs-extra'
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
6
|
+
import {
|
|
7
|
+
buildOutputPointerPath,
|
|
8
|
+
resolveServeOutDir,
|
|
9
|
+
writeBuildOutputPointer,
|
|
10
|
+
} from './buildOutputPointer'
|
|
11
|
+
|
|
12
|
+
describe('build output pointer', () => {
|
|
13
|
+
const originalCwd = process.cwd()
|
|
14
|
+
let tempRoot = ''
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
tempRoot = mkdtempSync(join(tmpdir(), 'one-build-pointer-'))
|
|
18
|
+
process.chdir(tempRoot)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
afterEach(async () => {
|
|
22
|
+
process.chdir(originalCwd)
|
|
23
|
+
vi.restoreAllMocks()
|
|
24
|
+
await FSExtra.remove(tempRoot)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('prefers an explicit serve outDir', async () => {
|
|
28
|
+
await FSExtra.ensureDir('build-out')
|
|
29
|
+
await FSExtra.writeJSON(join('build-out', 'buildInfo.json'), {})
|
|
30
|
+
await writeBuildOutputPointer('build-out')
|
|
31
|
+
|
|
32
|
+
expect(await resolveServeOutDir('manual-out')).toBe('manual-out')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('preserves serving from inside the output directory', async () => {
|
|
36
|
+
await FSExtra.writeJSON('buildInfo.json', {})
|
|
37
|
+
await FSExtra.ensureDir('build-out')
|
|
38
|
+
await FSExtra.writeJSON(join('build-out', 'buildInfo.json'), {})
|
|
39
|
+
await writeBuildOutputPointer('build-out')
|
|
40
|
+
|
|
41
|
+
expect(await resolveServeOutDir()).toBe('.')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('resolves the outDir written by build', async () => {
|
|
45
|
+
await FSExtra.ensureDir('build-out')
|
|
46
|
+
await FSExtra.writeJSON(join('build-out', 'buildInfo.json'), {})
|
|
47
|
+
|
|
48
|
+
await writeBuildOutputPointer('build-out')
|
|
49
|
+
|
|
50
|
+
expect(await FSExtra.readJSON(buildOutputPointerPath)).toEqual({
|
|
51
|
+
outDir: 'build-out',
|
|
52
|
+
})
|
|
53
|
+
expect(await resolveServeOutDir()).toBe('build-out')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('falls back to dist when the pointer is stale', async () => {
|
|
57
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
58
|
+
|
|
59
|
+
await writeBuildOutputPointer('missing-out')
|
|
60
|
+
|
|
61
|
+
expect(await resolveServeOutDir()).toBe('dist')
|
|
62
|
+
// both the stale-pointer warning and the missing-dist warning fire
|
|
63
|
+
expect(warn).toHaveBeenCalledTimes(2)
|
|
64
|
+
expect(warn.mock.calls[0][0]).toMatch(/build-pointer\.json points to/)
|
|
65
|
+
expect(warn.mock.calls[1][0]).toMatch(/no build-output pointer/)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('falls back to dist when no pointer exists and warns about missing dist', async () => {
|
|
69
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
70
|
+
|
|
71
|
+
expect(await resolveServeOutDir()).toBe('dist')
|
|
72
|
+
expect(warn).toHaveBeenCalledOnce()
|
|
73
|
+
expect(warn.mock.calls[0][0]).toMatch(/no build-output pointer/)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('does not warn when falling back to an existing dist/ build', async () => {
|
|
77
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
78
|
+
await FSExtra.ensureDir('dist')
|
|
79
|
+
await FSExtra.writeJSON(join('dist', 'buildInfo.json'), {})
|
|
80
|
+
|
|
81
|
+
expect(await resolveServeOutDir()).toBe('dist')
|
|
82
|
+
expect(warn).not.toHaveBeenCalled()
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('warns when the pointer write fails', async () => {
|
|
86
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
87
|
+
const writeSpy = vi
|
|
88
|
+
.spyOn(FSExtra, 'writeJSON')
|
|
89
|
+
.mockRejectedValueOnce(new Error('permission denied'))
|
|
90
|
+
|
|
91
|
+
await writeBuildOutputPointer('build-out')
|
|
92
|
+
|
|
93
|
+
expect(writeSpy).toHaveBeenCalled()
|
|
94
|
+
expect(warn).toHaveBeenCalledOnce()
|
|
95
|
+
expect(warn.mock.calls[0][0]).toMatch(/could not write build-output pointer/)
|
|
96
|
+
})
|
|
97
|
+
})
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { dirname, join } from 'node:path'
|
|
2
|
+
import FSExtra from 'fs-extra'
|
|
3
|
+
import { toAbsolute } from './toAbsolute'
|
|
4
|
+
|
|
5
|
+
// stored under the project cwd; one build and one serve should run from the same root.
|
|
6
|
+
export const buildOutputPointerPath = join(
|
|
7
|
+
'node_modules',
|
|
8
|
+
'.cache',
|
|
9
|
+
'one',
|
|
10
|
+
'build-pointer.json'
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
type BuildOutputPointer = {
|
|
14
|
+
outDir?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function writeBuildOutputPointer(outDir: string) {
|
|
18
|
+
try {
|
|
19
|
+
const pointerPath = toAbsolute(buildOutputPointerPath)
|
|
20
|
+
await FSExtra.ensureDir(dirname(pointerPath))
|
|
21
|
+
await FSExtra.writeJSON(pointerPath, { outDir })
|
|
22
|
+
} catch (err) {
|
|
23
|
+
// surface the failure so `one serve` doesn't later fall back to `dist/`
|
|
24
|
+
// with no breadcrumb when a custom outDir was used.
|
|
25
|
+
console.warn(
|
|
26
|
+
`[one build] could not write build-output pointer (${buildOutputPointerPath}). \`one serve\` will fall back to 'dist/' unless you pass --outDir.`,
|
|
27
|
+
err instanceof Error ? err.message : err
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function resolveServeOutDir(outDir?: string) {
|
|
33
|
+
if (outDir) {
|
|
34
|
+
return outDir
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (FSExtra.existsSync('buildInfo.json')) {
|
|
38
|
+
return '.'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ENOENT here is the common case (no pointer written yet); only warn on
|
|
42
|
+
// unexpected read errors.
|
|
43
|
+
let pointer: BuildOutputPointer | undefined
|
|
44
|
+
try {
|
|
45
|
+
pointer = (await FSExtra.readJSON(buildOutputPointerPath)) as BuildOutputPointer
|
|
46
|
+
} catch (err: any) {
|
|
47
|
+
if (err?.code && err.code !== 'ENOENT') {
|
|
48
|
+
console.warn(
|
|
49
|
+
`[one serve] could not read build-output pointer (${buildOutputPointerPath}):`,
|
|
50
|
+
err.message ?? err
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (pointer?.outDir) {
|
|
56
|
+
if (await FSExtra.pathExists(join(pointer.outDir, 'buildInfo.json'))) {
|
|
57
|
+
return pointer.outDir
|
|
58
|
+
}
|
|
59
|
+
console.warn(
|
|
60
|
+
`[one serve] build-pointer.json points to '${pointer.outDir}/' but no buildInfo.json was found there. run \`one build\` to refresh the marker.`
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!FSExtra.existsSync('dist/buildInfo.json')) {
|
|
65
|
+
console.warn(
|
|
66
|
+
`[one serve] no build-output pointer and no 'dist/buildInfo.json'. did \`one build\` run from this cwd? pass --outDir to point at the build output.`
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return 'dist'
|
|
71
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { isChunkLoadError, loadWithRetry } from './dynamicImport'
|
|
3
|
+
|
|
4
|
+
const instantDelay = () => Promise.resolve()
|
|
5
|
+
const chunkError = () =>
|
|
6
|
+
new Error('Failed to fetch dynamically imported module: /assets/EditorPane.js')
|
|
7
|
+
|
|
8
|
+
// let the all-microtask retry chain (instantDelay resolves synchronously) plus
|
|
9
|
+
// the final pending-promise branch fully drain before asserting.
|
|
10
|
+
const drain = () => new Promise((r) => setTimeout(r, 0))
|
|
11
|
+
|
|
12
|
+
describe('isChunkLoadError', () => {
|
|
13
|
+
it('matches the chrome / firefox / safari chunk-load messages, nothing else', () => {
|
|
14
|
+
expect(isChunkLoadError(new Error('Failed to fetch dynamically imported module: /a'))).toBe(
|
|
15
|
+
true
|
|
16
|
+
)
|
|
17
|
+
expect(isChunkLoadError(new Error('error loading dynamically imported module: /a'))).toBe(
|
|
18
|
+
true
|
|
19
|
+
)
|
|
20
|
+
expect(isChunkLoadError(new Error('Importing a module script failed.'))).toBe(true)
|
|
21
|
+
expect(isChunkLoadError('Failed to fetch dynamically imported module')).toBe(true)
|
|
22
|
+
expect(isChunkLoadError(new Error('TypeError: x is not a function'))).toBe(false)
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('loadWithRetry', () => {
|
|
27
|
+
it('resolves on first success without retrying or recovering', async () => {
|
|
28
|
+
const loader = vi.fn().mockResolvedValue({ default: 'ok' })
|
|
29
|
+
const delay = vi.fn(instantDelay)
|
|
30
|
+
const onChunkErrorExhausted = vi.fn(() => false)
|
|
31
|
+
await expect(loadWithRetry(loader, { delay, onChunkErrorExhausted })).resolves.toEqual({
|
|
32
|
+
default: 'ok',
|
|
33
|
+
})
|
|
34
|
+
expect(loader).toHaveBeenCalledTimes(1)
|
|
35
|
+
expect(delay).not.toHaveBeenCalled()
|
|
36
|
+
expect(onChunkErrorExhausted).not.toHaveBeenCalled()
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('retries a transient rejection then resolves, re-invoking the loader each attempt', async () => {
|
|
40
|
+
const loader = vi
|
|
41
|
+
.fn()
|
|
42
|
+
.mockRejectedValueOnce(chunkError())
|
|
43
|
+
.mockRejectedValueOnce(chunkError())
|
|
44
|
+
.mockResolvedValue({ default: 'ok' })
|
|
45
|
+
const delay = vi.fn(instantDelay)
|
|
46
|
+
const onChunkErrorExhausted = vi.fn(() => false)
|
|
47
|
+
await expect(
|
|
48
|
+
loadWithRetry(loader, { attempts: 3, delay, onChunkErrorExhausted })
|
|
49
|
+
).resolves.toEqual({ default: 'ok' })
|
|
50
|
+
expect(loader).toHaveBeenCalledTimes(3)
|
|
51
|
+
expect(delay).toHaveBeenCalledTimes(2)
|
|
52
|
+
expect(onChunkErrorExhausted).not.toHaveBeenCalled()
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('exhausts retries on a persistent chunk error, recovers once, and stays pending', async () => {
|
|
56
|
+
const loader = vi.fn().mockRejectedValue(chunkError())
|
|
57
|
+
const delay = vi.fn(instantDelay)
|
|
58
|
+
const onChunkErrorExhausted = vi.fn(() => true) // a reload was scheduled
|
|
59
|
+
const settled = vi.fn()
|
|
60
|
+
void loadWithRetry(loader, { attempts: 2, delay, onChunkErrorExhausted }).then(
|
|
61
|
+
settled,
|
|
62
|
+
settled
|
|
63
|
+
)
|
|
64
|
+
await drain()
|
|
65
|
+
expect(loader).toHaveBeenCalledTimes(3) // initial + 2 retries
|
|
66
|
+
expect(onChunkErrorExhausted).toHaveBeenCalledTimes(1)
|
|
67
|
+
// the page is tearing down for the reload — the promise must never settle so
|
|
68
|
+
// it can't flash a broken/blank tree.
|
|
69
|
+
expect(settled).not.toHaveBeenCalled()
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('rethrows a non-chunk error without recovering', async () => {
|
|
73
|
+
const loader = vi.fn().mockRejectedValue(new Error('boom: a real bug'))
|
|
74
|
+
const delay = vi.fn(instantDelay)
|
|
75
|
+
const onChunkErrorExhausted = vi.fn(() => true)
|
|
76
|
+
await expect(
|
|
77
|
+
loadWithRetry(loader, { attempts: 1, delay, onChunkErrorExhausted })
|
|
78
|
+
).rejects.toThrow('boom: a real bug')
|
|
79
|
+
expect(loader).toHaveBeenCalledTimes(2)
|
|
80
|
+
expect(onChunkErrorExhausted).not.toHaveBeenCalled()
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('rethrows a chunk error when the reload was debounced away', async () => {
|
|
84
|
+
const loader = vi.fn().mockRejectedValue(chunkError())
|
|
85
|
+
const delay = vi.fn(instantDelay)
|
|
86
|
+
const onChunkErrorExhausted = vi.fn(() => false) // debounced, no reload happened
|
|
87
|
+
await expect(
|
|
88
|
+
loadWithRetry(loader, { attempts: 1, delay, onChunkErrorExhausted })
|
|
89
|
+
).rejects.toThrow('Failed to fetch dynamically imported module')
|
|
90
|
+
expect(onChunkErrorExhausted).toHaveBeenCalledTimes(1)
|
|
91
|
+
})
|
|
92
|
+
})
|
|
@@ -9,17 +9,23 @@ export const dynamicImport = (path: string) => {
|
|
|
9
9
|
return Promise.resolve(undefined)
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
// retry a transient chunk-fetch failure in place before giving up, then fall
|
|
13
|
+
// back to one's debounced reload. the in-place retry matters because a single
|
|
14
|
+
// rejection permanently poisons callers that memoize the loader result — most
|
|
15
|
+
// notably React.lazy, which caches the FIRST settled value (rejection
|
|
16
|
+
// included) and re-throws it forever without re-invoking the loader. the retry
|
|
17
|
+
// is always cheap; only the reload honors the ONE_SKEW_PROTECTION opt-out.
|
|
18
|
+
return loadWithRetry(
|
|
19
|
+
() =>
|
|
20
|
+
import(
|
|
21
|
+
/* @vite-ignore */
|
|
22
|
+
path
|
|
23
|
+
),
|
|
24
|
+
{
|
|
25
|
+
onChunkErrorExhausted: () =>
|
|
26
|
+
process.env.ONE_SKEW_PROTECTION !== 'false' ? handleSkewError() : false,
|
|
27
|
+
}
|
|
28
|
+
)
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
const CHUNK_ERROR_PATTERNS = [
|
|
@@ -33,12 +39,73 @@ export function isChunkLoadError(err: unknown): boolean {
|
|
|
33
39
|
return CHUNK_ERROR_PATTERNS.some((p) => msg.includes(p))
|
|
34
40
|
}
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
// debounced one-time reload to recover from a deploy skew or a poisoned dev
|
|
43
|
+
// module graph. returns whether it actually scheduled a reload (false when
|
|
44
|
+
// debounced away within the cooldown, or on the server) so callers like
|
|
45
|
+
// loadWithRetry can decide whether to keep waiting for the teardown or surface
|
|
46
|
+
// the underlying error.
|
|
47
|
+
export function handleSkewError(): boolean {
|
|
48
|
+
if (typeof window === 'undefined') return false
|
|
38
49
|
const key = '__one_skew_reload'
|
|
39
50
|
const last = sessionStorage.getItem(key)
|
|
40
51
|
if (!last || Date.now() - Number(last) > 10_000) {
|
|
41
52
|
sessionStorage.setItem(key, String(Date.now()))
|
|
42
53
|
window.location.reload()
|
|
54
|
+
return true
|
|
55
|
+
}
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// extra attempts after the first before giving up. a transient chunk fetch
|
|
60
|
+
// (ECONNRESET / dev-server 5xx / timeout under load) usually recovers on the
|
|
61
|
+
// next try when the failure is the top-level chunk.
|
|
62
|
+
export const CHUNK_RETRY_ATTEMPTS = 3
|
|
63
|
+
// linear backoff between chunk retries: ride out a brief hiccup, not a long
|
|
64
|
+
// outage.
|
|
65
|
+
export const CHUNK_RETRY_DELAY_MS = 500
|
|
66
|
+
|
|
67
|
+
const realDelay = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms))
|
|
68
|
+
|
|
69
|
+
// wraps a dynamic-import loader so a transient rejection is retried with backoff
|
|
70
|
+
// before it settles, instead of permanently poisoning a caller that memoizes the
|
|
71
|
+
// result (e.g. React.lazy — see dynamicImport above, and lazyWithRetry). when
|
|
72
|
+
// retries are exhausted on a chunk-load error, recover via the injected reload
|
|
73
|
+
// (defaults to one's debounced handleSkewError); the reload tears the page down,
|
|
74
|
+
// so the returned promise is left pending rather than rejecting into a surviving
|
|
75
|
+
// tree. `delay` + `onChunkErrorExhausted` are injectable so this is unit-testable
|
|
76
|
+
// without real timers or a real location.reload.
|
|
77
|
+
export async function loadWithRetry<T>(
|
|
78
|
+
loader: () => Promise<T>,
|
|
79
|
+
options: {
|
|
80
|
+
attempts?: number
|
|
81
|
+
delayMs?: number
|
|
82
|
+
delay?: (ms: number) => Promise<void>
|
|
83
|
+
onChunkErrorExhausted?: () => boolean
|
|
84
|
+
} = {}
|
|
85
|
+
): Promise<T> {
|
|
86
|
+
const attempts = options.attempts ?? CHUNK_RETRY_ATTEMPTS
|
|
87
|
+
const delayMs = options.delayMs ?? CHUNK_RETRY_DELAY_MS
|
|
88
|
+
const delay = options.delay ?? realDelay
|
|
89
|
+
const recover = options.onChunkErrorExhausted ?? handleSkewError
|
|
90
|
+
|
|
91
|
+
const attempt = async (retriesLeft: number): Promise<T> => {
|
|
92
|
+
try {
|
|
93
|
+
return await loader()
|
|
94
|
+
} catch (err) {
|
|
95
|
+
if (retriesLeft > 0) {
|
|
96
|
+
await delay(delayMs)
|
|
97
|
+
return attempt(retriesLeft - 1)
|
|
98
|
+
}
|
|
99
|
+
// out of retries: a chunk-load failure is a dev module-graph poison or a
|
|
100
|
+
// prod deploy skew — recover via the debounced reload. the reload tears the
|
|
101
|
+
// page down, so leave this promise pending (resolving/rejecting would
|
|
102
|
+
// flash a broken tree). if the reload was debounced away, surface the real
|
|
103
|
+
// error so it isn't swallowed.
|
|
104
|
+
if (isChunkLoadError(err) && recover()) {
|
|
105
|
+
return new Promise<T>(() => {})
|
|
106
|
+
}
|
|
107
|
+
throw err
|
|
108
|
+
}
|
|
43
109
|
}
|
|
110
|
+
return attempt(attempts)
|
|
44
111
|
}
|