@@ -85,7 +85,7 @@ import {
8585 parseStack ,
8686} from 'next/dist/compiled/@next/react-dev-overlay/dist/middleware'
8787import { BuildManifest } from '../../get-page-files'
88- import { mkdir , readFile , writeFile } from 'fs/promises'
88+ import { mkdir , readFile , writeFile , rename , unlink } from 'fs/promises'
8989import { PagesManifest } from '../../../build/webpack/plugins/pages-manifest-plugin'
9090import { AppBuildManifest } from '../../../build/webpack/plugins/app-build-manifest-plugin'
9191import { PageNotFoundError } from '../../../shared/lib/utils'
@@ -692,14 +692,31 @@ async function startWatcher(opts: SetupOpts) {
692692 return manifest
693693 }
694694
695+ async function writeFileAtomic (
696+ filePath : string ,
697+ content : string
698+ ) : Promise < void > {
699+ const tempPath = filePath + '.tmp.' + Math . random ( ) . toString ( 36 ) . slice ( 2 )
700+ try {
701+ await writeFile ( tempPath , content , 'utf-8' )
702+ await rename ( tempPath , filePath )
703+ } catch ( e ) {
704+ try {
705+ await unlink ( tempPath )
706+ } catch {
707+ // ignore
708+ }
709+ throw e
710+ }
711+ }
712+
695713 async function writeBuildManifest ( ) : Promise < void > {
696714 const buildManifest = mergeBuildManifests ( buildManifests . values ( ) )
697715 const buildManifestPath = path . join ( distDir , BUILD_MANIFEST )
698716 deleteCache ( buildManifestPath )
699- await writeFile (
717+ await writeFileAtomic (
700718 buildManifestPath ,
701- JSON . stringify ( buildManifest , null , 2 ) ,
702- 'utf-8'
719+ JSON . stringify ( buildManifest , null , 2 )
703720 )
704721 const content = {
705722 __rewrites : { afterFiles : [ ] , beforeFiles : [ ] , fallback : [ ] } ,
@@ -714,15 +731,13 @@ async function startWatcher(opts: SetupOpts) {
714731 const buildManifestJs = `self.__BUILD_MANIFEST = ${ JSON . stringify (
715732 content
716733 ) } ;self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB()`
717- await writeFile (
734+ await writeFileAtomic (
718735 path . join ( distDir , 'static' , 'development' , '_buildManifest.js' ) ,
719- buildManifestJs ,
720- 'utf-8'
736+ buildManifestJs
721737 )
722- await writeFile (
738+ await writeFileAtomic (
723739 path . join ( distDir , 'static' , 'development' , '_ssgManifest.js' ) ,
724- srcEmptySsgManifest ,
725- 'utf-8'
740+ srcEmptySsgManifest
726741 )
727742 }
728743
@@ -737,10 +752,9 @@ async function startWatcher(opts: SetupOpts) {
737752 `fallback-${ BUILD_MANIFEST } `
738753 )
739754 deleteCache ( fallbackBuildManifestPath )
740- await writeFile (
755+ await writeFileAtomic (
741756 fallbackBuildManifestPath ,
742- JSON . stringify ( fallbackBuildManifest , null , 2 ) ,
743- 'utf-8'
757+ JSON . stringify ( fallbackBuildManifest , null , 2 )
744758 )
745759 }
746760
@@ -750,21 +764,19 @@ async function startWatcher(opts: SetupOpts) {
750764 )
751765 const appBuildManifestPath = path . join ( distDir , APP_BUILD_MANIFEST )
752766 deleteCache ( appBuildManifestPath )
753- await writeFile (
767+ await writeFileAtomic (
754768 appBuildManifestPath ,
755- JSON . stringify ( appBuildManifest , null , 2 ) ,
756- 'utf-8'
769+ JSON . stringify ( appBuildManifest , null , 2 )
757770 )
758771 }
759772
760773 async function writePagesManifest ( ) : Promise < void > {
761774 const pagesManifest = mergePagesManifests ( pagesManifests . values ( ) )
762775 const pagesManifestPath = path . join ( distDir , 'server' , PAGES_MANIFEST )
763776 deleteCache ( pagesManifestPath )
764- await writeFile (
777+ await writeFileAtomic (
765778 pagesManifestPath ,
766- JSON . stringify ( pagesManifest , null , 2 ) ,
767- 'utf-8'
779+ JSON . stringify ( pagesManifest , null , 2 )
768780 )
769781 }
770782
@@ -776,10 +788,9 @@ async function startWatcher(opts: SetupOpts) {
776788 APP_PATHS_MANIFEST
777789 )
778790 deleteCache ( appPathsManifestPath )
779- await writeFile (
791+ await writeFileAtomic (
780792 appPathsManifestPath ,
781- JSON . stringify ( appPathsManifest , null , 2 ) ,
782- 'utf-8'
793+ JSON . stringify ( appPathsManifest , null , 2 )
783794 )
784795 }
785796
@@ -792,10 +803,9 @@ async function startWatcher(opts: SetupOpts) {
792803 'server/middleware-manifest.json'
793804 )
794805 deleteCache ( middlewareManifestPath )
795- await writeFile (
806+ await writeFileAtomic (
796807 middlewareManifestPath ,
797- JSON . stringify ( middlewareManifest , null , 2 ) ,
798- 'utf-8'
808+ JSON . stringify ( middlewareManifest , null , 2 )
799809 )
800810 }
801811
@@ -808,7 +818,7 @@ async function startWatcher(opts: SetupOpts) {
808818 NEXT_FONT_MANIFEST + '.json'
809819 )
810820 deleteCache ( fontManifestPath )
811- await writeFile (
821+ await writeFileAtomic (
812822 fontManifestPath ,
813823 JSON . stringify (
814824 {
@@ -829,11 +839,7 @@ async function startWatcher(opts: SetupOpts) {
829839 'react-loadable-manifest.json'
830840 )
831841 deleteCache ( loadableManifestPath )
832- await writeFile (
833- loadableManifestPath ,
834- JSON . stringify ( { } , null , 2 ) ,
835- 'utf-8'
836- )
842+ await writeFileAtomic ( loadableManifestPath , JSON . stringify ( { } , null , 2 ) )
837843 }
838844
839845 async function subscribeToHmrEvents ( id : string , client : ws ) {
0 commit comments