diff --git a/example/app.json b/example/app.json index b68f9837e..c1f4fa7e4 100644 --- a/example/app.json +++ b/example/app.json @@ -22,7 +22,7 @@ ], "windows": [ "dist/assets", - "dist/main.windows.jsbundle" + "dist/main.windows.bundle" ] } } diff --git a/windows/ReactTestApp.sln b/windows/ReactTestApp.sln index 82fd7da75..9a3694715 100644 --- a/windows/ReactTestApp.sln +++ b/windows/ReactTestApp.sln @@ -3,47 +3,47 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30204.135 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactTestApp", "ReactTestApp\ReactTestApp.vcxproj", "{B44CEAD7-FBFF-4A17-95EA-FF5434BBD79D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactTestApp", "$(ReactTestAppProjectPath)\ReactTestApp.vcxproj", "{B44CEAD7-FBFF-4A17-95EA-FF5434BBD79D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ReactNative", "ReactNative", "{545EBB52-51A5-448C-A9C7-8D1E8FDD4829}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\node_modules\react-native-windows\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "$(ReactNativeModulePath)\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\node_modules\react-native-windows\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "$(ReactNativeModulePath)\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactWindowsCore", "..\node_modules\react-native-windows\ReactWindowsCore\ReactWindowsCore.vcxproj", "{11C084A3-A57C-4296-A679-CAC17B603144}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactWindowsCore", "$(ReactNativeModulePath)\ReactWindowsCore\ReactWindowsCore.vcxproj", "{11C084A3-A57C-4296-A679-CAC17B603144}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "..\node_modules\react-native-windows\Common\Common.vcxproj", "{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "$(ReactNativeModulePath)\Common\Common.vcxproj", "{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSI.Universal", "..\node_modules\react-native-windows\JSI\Universal\JSI.Universal.vcxproj", "{A62D504A-16B8-41D2-9F19-E2E86019E5E4}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSI.Universal", "$(ReactNativeModulePath)\JSI\Universal\JSI.Universal.vcxproj", "{A62D504A-16B8-41D2-9F19-E2E86019E5E4}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra", "..\node_modules\react-native-windows\Chakra\Chakra.vcxitems", "{C38970C0-5FBF-4D69-90D8-CBAC225AE895}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra", "$(ReactNativeModulePath)\Chakra\Chakra.vcxitems", "{C38970C0-5FBF-4D69-90D8-CBAC225AE895}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSI.Shared", "..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems", "{0CC28589-39E4-4288-B162-97B959F8B843}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSI.Shared", "$(ReactNativeModulePath)\JSI\Shared\JSI.Shared.vcxitems", "{0CC28589-39E4-4288-B162-97B959F8B843}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\node_modules\react-native-windows\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "$(ReactNativeModulePath)\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Cxx", "..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems", "{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Cxx", "$(ReactNativeModulePath)\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems", "{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mso", "..\node_modules\react-native-windows\Mso\Mso.vcxitems", "{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mso", "$(ReactNativeModulePath)\Mso\Mso.vcxitems", "{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Shared", "..\node_modules\react-native-windows\Shared\Shared.vcxitems", "{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Shared", "$(ReactNativeModulePath)\Shared\Shared.vcxitems", "{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution - ..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{0cc28589-39e4-4288-b162-97b959f8b843}*SharedItemsImports = 9 - ..\node_modules\react-native-windows\ReactWindowsCore\ReactWindowsCore.vcxitems*{11c084a3-a57c-4296-a679-cac17b603144}*SharedItemsImports = 4 - ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9 - ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9 - ..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{a62d504a-16b8-41d2-9f19-e2e86019e5e4}*SharedItemsImports = 4 - ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{b44cead7-fbff-4a17-95ea-ff5434bbd79d}*SharedItemsImports = 4 - ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9 - ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9 - ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 - ..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 - ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 - ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 - ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 + $(ReactNativeModulePath)\JSI\Shared\JSI.Shared.vcxitems*{0cc28589-39e4-4288-b162-97b959f8b843}*SharedItemsImports = 9 + $(ReactNativeModulePath)\ReactWindowsCore\ReactWindowsCore.vcxitems*{11c084a3-a57c-4296-a679-cac17b603144}*SharedItemsImports = 4 + $(ReactNativeModulePath)\Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9 + $(ReactNativeModulePath)\Mso\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9 + $(ReactNativeModulePath)\JSI\Shared\JSI.Shared.vcxitems*{a62d504a-16b8-41d2-9f19-e2e86019e5e4}*SharedItemsImports = 4 + $(ReactNativeModulePath)\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{b44cead7-fbff-4a17-95ea-ff5434bbd79d}*SharedItemsImports = 4 + $(ReactNativeModulePath)\Chakra\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9 + $(ReactNativeModulePath)\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9 + $(ReactNativeModulePath)\Chakra\Chakra.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 + $(ReactNativeModulePath)\JSI\Shared\JSI.Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 + $(ReactNativeModulePath)\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 + $(ReactNativeModulePath)\Mso\Mso.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 + $(ReactNativeModulePath)\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM diff --git a/windows/ReactTestApp/ReactTestApp.vcxproj b/windows/ReactTestApp/ReactTestApp.vcxproj index fb8255af9..0e335be52 100644 --- a/windows/ReactTestApp/ReactTestApp.vcxproj +++ b/windows/ReactTestApp/ReactTestApp.vcxproj @@ -1,6 +1,6 @@ - + true true @@ -58,8 +58,10 @@ v141 v142 Unicode - ..\..\example\dist - $(BundleContentRoot)\**\* + $(BundleDirContentPaths) + $(BundleFileContentPaths) + $(SourceFilesPath)\Assets + $(AssetsContentRoot)\**\* true @@ -74,7 +76,7 @@ - + @@ -82,7 +84,30 @@ - + + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(SourceFilesPath) + + + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(SourceFilesPath) + + + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(SourceFilesPath) + + + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(SourceFilesPath) + + + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(SourceFilesPath) + + + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(SourceFilesPath) + + + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(SourceFilesPath) + + + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(SourceFilesPath) + Use @@ -116,59 +141,59 @@ - - - - App.xaml + + + + $(SourceFilesPath)\App.xaml - - MainPage.xaml + + $(SourceFilesPath)\MainPage.xaml - + - + Designer - + Designer - + Designer - - - - - - - - + + + $([MSBuild]::MakeRelative($(ProjectDir),'Assets\%(RecursiveDir)%(Filename)%(Extension)')) + true + + + + - + Create - - App.xaml + + $(SourceFilesPath)\App.xaml - - MainPage.xaml + + $(SourceFilesPath)\MainPage.xaml - - + + - - App.xaml + + $(SourceFilesPath)\App.xaml - - MainPage.xaml + + $(SourceFilesPath)\MainPage.xaml @@ -176,44 +201,53 @@ - - + + + $([MSBuild]::ValueOrDefault('%(FullPath)', '').Remove($([MSBuild]::ValueOrDefault(%(FullPath), '').LastIndexOf(\%(RecursiveDir)%(Filename)%(Extension))))) + $([MSBuild]::ValueOrDefault(%(DirNameFullPath), '').Substring($([MSBuild]::ValueOrDefault(%(DirNameFullPath), '').LastIndexOf('\')))) + $([MSBuild]::MakeRelative($(ProjectDir),'Bundle%(DirName)\%(RecursiveDir)%(Filename)%(Extension)')) + true + + + + + $([MSBuild]::MakeRelative($(ProjectDir),'Bundle\%(RecursiveDir)%(Filename)%(Extension)')) true - + {fca38f3c-7c73-4c47-be4e-32f77fa8538d} - + {a990658c-ce31-4bcc-976f-0fc6b1af693d} - + {a62d504a-16b8-41d2-9f19-e2e86019e5e4} - + {f7d32bd0-2749-483e-9a0d-1635ef7e3136} false - + {a9d95a91-4db7-4f72-beb6-fe8a5c89bfbd} - + {11c084a3-a57c-4296-a679-cac17b603144} - - + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + diff --git a/windows/ReactTestApp/ReactTestApp.vcxproj.filters b/windows/ReactTestApp/ReactTestApp.vcxproj.filters index 17d45f2f0..674877b51 100644 --- a/windows/ReactTestApp/ReactTestApp.vcxproj.filters +++ b/windows/ReactTestApp/ReactTestApp.vcxproj.filters @@ -1,62 +1,40 @@ - + - + - - + + - - - + + + - - + + - - - + + + - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - + Assets - + {e48dc53e-40b1-40cb-970a-f89935452892} - diff --git a/windows/test-app.js b/windows/test-app.js new file mode 100644 index 000000000..73b9dfee9 --- /dev/null +++ b/windows/test-app.js @@ -0,0 +1,234 @@ +//@ts-check +const path = require("path"); +const fs = require("fs"); +const chalk = require("chalk"); + +const windowsDir = "windows"; +const nodeModulesDir = "node_modules"; +const generatedDir = ".generated"; +const closestNodeModules = findClosestPathTo(nodeModulesDir); +const reactNativeModulePath = findClosestPathTo( + path.join(nodeModulesDir, "react-native-windows") +); +const testAppNodeModulePath = findClosestPathTo( + path.join(nodeModulesDir, "react-native-test-app") +); +const destPath = path.resolve(""); + +function findClosestPathTo(fileOrDirName) { + let basePath = path.resolve(""); + const rootDirectory = basePath.split(path.sep)[0] + path.sep; + + while (basePath !== rootDirectory) { + const candidatePath = path.join(basePath, fileOrDirName); + if (fs.existsSync(candidatePath)) { + return path.relative("", candidatePath); + } + //Get parent folder + basePath = path.dirname(basePath); + } + + return null; +} + +/** + * Get a source file and replace parts of its contents. + * @param srcPath Path to the source file. + * @param replacements e.g. {'TextToBeReplaced': 'Replacement'} + * @return The contents of the file with the replacements applied. + */ +function resolveContents(srcPath, replacements) { + const content = fs.readFileSync(srcPath, "utf8"); + + return Object.keys(replacements).reduce((content, regex) => { + return content.replace(new RegExp(regex, "g"), replacements[regex]); + }, content); +} + +//Binary files in React Native Test App Windows project +const binaryExtensions = [".png", ".pfx"]; + +/** + * Copy a file to given destination, replacing parts of its contents. + * @param srcPath Path to a file to be copied. + * @param destPath Destination path. + * @param replacements: e.g. {'TextToBeReplaced': 'Replacement'} + */ +function copyAndReplace( + srcPath, + destPath, + relativeDestPath, + replacements = {} +) { + const fullDestPath = path.join(destPath, relativeDestPath); + if (fs.lstatSync(srcPath).isDirectory()) { + if (!fs.existsSync(fullDestPath)) { + fs.mkdirSync(fullDestPath); + } + return; + } + + const extension = path.extname(srcPath); + if (binaryExtensions.indexOf(extension) !== -1) { + // Binary file + fs.copyFile(srcPath, fullDestPath, (err) => { + if (err) { + throw err; + } + }); + } else { + // Text file + const srcPermissions = fs.statSync(srcPath).mode; + const content = resolveContents(srcPath, replacements); + fs.writeFile( + fullDestPath, + content, + { + encoding: "utf8", + mode: srcPermissions, + }, + (err) => { + if (err) { + throw err; + } + } + ); + } +} + +function copyProjectTemplateAndReplace( + destPath, + nodeModulesPath, + reactNativeModulePath, + testAppNodeModulePath +) { + if (!destPath) { + throw new Error("Need a path to copy to"); + } + + if (!reactNativeModulePath) { + throw new Error("react-native-windows node module is not installed"); + } + + if (!testAppNodeModulePath) { + throw new Error("react-native-test-app node module is not installed"); + } + + const srcRootPath = path.join(testAppNodeModulePath, windowsDir); + const projDir = "ReactTestApp"; + const projectFilesDestPath = path.join( + nodeModulesPath, + generatedDir, + windowsDir, + projDir + ); + + fs.mkdirSync(projectFilesDestPath, { recursive: true }); + fs.mkdirSync(path.join(destPath, windowsDir), { recursive: true }); + + const manifestFilePath = findClosestPathTo("app.json"); + + //Read path to resources from manifest + let bundleDirContent = ""; + let bundleFileContent = ""; + const content = fs.readFileSync(manifestFilePath); + let resourcesPaths = {}; + try { + resourcesPaths = JSON.parse(content.toString()).resources; + } catch (e) { + console.warn(chalk.red(`Couldn't parse app.json: \n${e.message}`)); + } + resourcesPaths = (resourcesPaths && resourcesPaths.windows) || resourcesPaths; + if (Array.isArray(resourcesPaths)) { + for (const resource of resourcesPaths) { + const resourceSrcPath = path.relative( + path.dirname(manifestFilePath), + resource + ); + if (fs.existsSync(resourceSrcPath)) { + let relativeResourcePath = path.relative( + projectFilesDestPath, + resourceSrcPath + ); + if (fs.statSync(resourceSrcPath).isDirectory()) { + relativeResourcePath = relativeResourcePath.concat("\\**\\*"); + bundleDirContent = bundleDirContent.concat( + relativeResourcePath + ";" + ); + } else { + bundleFileContent = bundleFileContent.concat( + relativeResourcePath + ";" + ); + } + } else { + console.warn( + chalk.yellow(`warning: resource with path ${resource} was not found`) + ); + } + } + } + + const projectFilesReplacements = { + "\\$\\(ManifestRootPath\\)": path.relative( + projectFilesDestPath, + path.dirname(manifestFilePath) + ), + "\\$\\(ReactNativeModulePath\\)": path.relative( + projectFilesDestPath, + reactNativeModulePath + ), + "\\$\\(SourceFilesPath\\)": path.relative( + projectFilesDestPath, + path.join(srcRootPath, projDir) + ), + "\\$\\(BundleDirContentPaths\\)": bundleDirContent, + "\\$\\(BundleFileContentPaths\\)": bundleFileContent, + }; + + const projectFilesMappings = [ + "ReactTestApp.vcxproj", + "PropertySheet.props", + "Package.appxmanifest", + "ReactTestApp.vcxproj.filters", + "ReactTestApp_TemporaryKey.pfx", + "packages.config", + ].map((file) => ({ + from: path.join(srcRootPath, projDir, file), + to: path.join(projectFilesDestPath, file), + })); + + for (const mapping of projectFilesMappings) { + copyAndReplace( + mapping.from, + destPath, + mapping.to, + projectFilesReplacements + ); + } + + const solutionFileDestPath = path.join(destPath, windowsDir); + const solutionFileReplacements = { + "\\$\\(ReactNativeModulePath\\)": path.relative( + solutionFileDestPath, + reactNativeModulePath + ), + "\\$\\(ReactTestAppProjectPath\\)": path.relative( + solutionFileDestPath, + projectFilesDestPath + ), + }; + + copyAndReplace( + path.join(srcRootPath, "ReactTestApp.sln"), + destPath, + path.join(windowsDir, "ReactTestApp.sln"), + solutionFileReplacements + ); +} + +copyProjectTemplateAndReplace( + destPath, + closestNodeModules, + reactNativeModulePath, + testAppNodeModulePath +);