UNPKG

@rnv/engine-rn-windows

Version:

ReNative Engine to build for Windows platform with react native support.

410 lines 24.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.copyProjectTemplateAndReplace = void 0; var tslib_1 = require("tslib"); /** * Copyright (c) Microsoft Corporation. * Licensed under the MIT License. * @format */ // DEPS var core_1 = require("@rnv/core"); var path = require('path'); var username = require('username'); var uuid = require('uuid'); var childProcess = require('child_process'); var fs = require('fs'); var os = require('os'); // eslint-disable-next-line no-unused-vars // const _ = require('lodash'); var findUp = require('find-up'); var generator_common_1 = require('./generator-common'); var configUtils_1 = require('./config/configUtils'); // EXTRACTS FROM RNV var getAppFolder = core_1.Common.getAppFolder, getAppTitle = core_1.Common.getAppTitle, getConfigProp = core_1.Common.getConfigProp; var copyFolderContentsRecursive = core_1.FileUtils.copyFolderContentsRecursive, copyFolderContentsRecursiveSync = core_1.FileUtils.copyFolderContentsRecursiveSync; var logError = core_1.Logger.logError, logDefault = core_1.Logger.logDefault, logInfo = core_1.Logger.logInfo, logWarning = core_1.Logger.logWarning, logSuccess = core_1.Logger.logSuccess; var copyAssetsFolder = core_1.ProjectManager.copyAssetsFolder; // CONSTS var bundleDir = 'Bundle'; // FUNCTIONS function generateCertificate(srcPath, currentUser, c, options) { return tslib_1.__awaiter(this, void 0, void 0, function () { var appFolder, timeout, thumbprint; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: logDefault('Generating self-signed certificate'); appFolder = getAppFolder(true); if (os.platform() === 'win32') { try { timeout = 10000; thumbprint = childProcess .execSync( // eslint-disable-next-line max-len "powershell -NoProfile -Command \"Write-Output (New-SelfSignedCertificate -KeyUsage DigitalSignature -KeyExportPolicy Exportable -Subject 'CN=".concat(currentUser, "' -TextExtension @('2.5.29.37={text}1.3.6.1.5.5.7.3.3', '2.5.29.19={text}Subject Type:End Entity') -CertStoreLocation 'Cert:\\CurrentUser\\My').Thumbprint\""), { timeout: timeout }) .toString() .trim(); childProcess.execSync( // eslint-disable-next-line max-len "powershell -NoProfile -Command \"$pwd = (ConvertTo-SecureString -String password -Force -AsPlainText); Export-PfxCertificate -Cert 'cert:\\CurrentUser\\My\\".concat(thumbprint, "' -FilePath ").concat(path.join(appFolder, c.runtime.appId, c.runtime.appId), "_TemporaryKey.pfx -Password $pwd\""), { timeout: timeout }); logSuccess('Self-signed certificate generated successfully.'); return [2 /*return*/, thumbprint]; } catch (err) { logError('Failed to generate Self-signed certificate.'); } } logWarning('Using Default Certificate. Use Visual Studio to renew it.'); return [4 /*yield*/, generator_common_1.copyAndReplaceWithChangedCallback(path.join(srcPath, 'keys', 'MyApp_TemporaryKey.pfx'), c.paths.project.dir, path.join(appFolder, c.runtime.appId, "".concat(c.runtime.appId, "_TemporaryKey.pfx")), undefined, options)]; case 1: _a.sent(); return [2 /*return*/, null]; } }); }); } // Existing high cyclomatic complexity function copyProjectTemplateAndReplace(c, options) { return tslib_1.__awaiter(this, void 0, void 0, function () { var appTitle, appFolder, RNIconsPluginPath, language, experimentalNuGetDependency, useWinUI3, nuGetTestVersion, useHermes, nuGetTestFeed, namespaceCpp, reactNative, rnVersion, RNWTemplatePath, srcPath, sharedPath, projDir, projectGuid, rnwVersion, nugetVersion, packageGuid, currentUser, mainComponentName, appJsonPath, certificateThumbprint, xamlNamespace, xamlNamespaceCpp, winui3PropsPath, winui3Props, winui3Version, csNugetPackages, cppNugetPackages, isMonorepo, monoRoot, templateVars, commonMappings, _i, commonMappings_1, mapping, csMappings, _a, csMappings_1, mapping, cppMappings, _b, cppMappings_1, mapping, sharedProjMappings, _c, sharedProjMappings_1, mapping, appFolderFull, glyphmapsDir, RNIconsGlyphmapsPluginPath; return tslib_1.__generator(this, function (_d) { switch (_d.label) { case 0: if (!c.paths.project.dir) { throw new Error('Need a path to copy to'); } appTitle = getAppTitle(); appFolder = getAppFolder(true); RNIconsPluginPath = path.join(path.dirname(require.resolve('react-native-vector-icons/package.json', { paths: [c.paths.project.dir], })), 'Fonts'); language = getConfigProp('language', options.language); experimentalNuGetDependency = getConfigProp(c, c.platform, 'experimentalNuGetDependency', options.experimentalNuGetDependency); useWinUI3 = getConfigProp('useWinUI3', options.useWinUI3); nuGetTestVersion = getConfigProp('nuGetTestVersion', options.nuGetTestVersion); useHermes = !!getConfigProp('reactNativeEngine', options.reactNativeEngine) === 'hermes'; nuGetTestFeed = getConfigProp('nuGetTestFeed', options.nuGetTestFeed); generator_common_1.createDir(path.join(c.paths.project.dir, appFolder)); generator_common_1.createDir(path.join(c.paths.project.dir, appFolder, c.runtime.appId)); generator_common_1.createDir(path.join(c.paths.project.dir, appFolder, c.runtime.appId, bundleDir)); generator_common_1.createDir(path.join(c.paths.project.dir, appFolder, c.runtime.appId, 'BundleBuilder')); namespaceCpp = toCppNamespace(c.runtime.appId); if (experimentalNuGetDependency) { logInfo('Using experimental NuGet dependency.'); } if (useWinUI3) { logInfo('Using experimental WinUI3 dependency.'); } reactNative = require('react-native/package.json'); rnVersion = parseFloat(reactNative.version); // In 0.64 version of RN Windows the location was changed and some folders were renamed (separation between lib abd app) if (rnVersion >= 0.64) { RNWTemplatePath = path.join(path.dirname(require.resolve('react-native-windows/package.json', { paths: [c.paths.project.dir], })), 'template'); // TODO Add support for developing libs, not just apps using renative (RN Windows added this in 0.64 version) srcPath = path.join(RNWTemplatePath, "".concat(language, "-app")); sharedPath = path.join(RNWTemplatePath, 'shared-app'); } else if (rnVersion >= 0.63) { RNWTemplatePath = path.join(path.dirname(require.resolve('@react-native-windows/cli/package.json', { paths: [c.paths.project.dir], })), 'templates'); srcPath = path.join(RNWTemplatePath, "".concat(language)); sharedPath = path.join(RNWTemplatePath, 'shared'); } else { logError("ReNative's React Native Windows engine does not support version of React Native older than 0.63"); } projDir = 'proj'; projectGuid = uuid.v4(); rnwVersion = require('react-native-windows/package.json').version; nugetVersion = nuGetTestVersion || rnwVersion; packageGuid = uuid.v4(); currentUser = username.sync(); mainComponentName = c.runtime.appId; return [4 /*yield*/, findUp('app.json', { cwd: c.paths.project.dir })]; case 1: appJsonPath = _d.sent(); if (appJsonPath) { mainComponentName = JSON.parse(fs.readFileSync(appJsonPath, 'utf8')).name; } if (!!fs.existsSync(path.join(appFolder, c.runtime.appId, "".concat(c.runtime.appId, "_TemporaryKey.pfx")))) return [3 /*break*/, 3]; return [4 /*yield*/, generateCertificate(srcPath, currentUser, c, options)]; case 2: certificateThumbprint = _d.sent(); return [3 /*break*/, 4]; case 3: logInfo('[generateCertificate] Certificate already exists, skipping generation of a new one.'); _d.label = 4; case 4: xamlNamespace = useWinUI3 ? 'Microsoft.UI.Xaml' : 'Windows.UI.Xaml'; xamlNamespaceCpp = toCppNamespace(xamlNamespace); winui3PropsPath = require.resolve('react-native-windows/PropertySheets/WinUI.props', { paths: [process.cwd()], }); winui3Props = configUtils_1.readProjectFile(winui3PropsPath); winui3Version = configUtils_1.findPropertyValue(winui3Props, 'WinUI3Version', winui3PropsPath); csNugetPackages = [ { id: 'Microsoft.NETCore.UniversalWindowsPlatform', version: '6.2.9', }, ]; cppNugetPackages = [ { id: 'Microsoft.Windows.CppWinRT', version: rnVersion > 0.64 ? '2.0.210312.4' : '2.0.200615.7', propsTopOfFile: true, hasProps: true, hasTargets: true, }, { id: useWinUI3 ? 'Microsoft.WinUI' : 'Microsoft.UI.Xaml', version: useWinUI3 ? winui3Version : '2.3.191129002', hasProps: false, hasTargets: false, }, ]; if (experimentalNuGetDependency) { csNugetPackages.push({ id: 'Microsoft.ReactNative.Managed', version: nugetVersion, }); cppNugetPackages.push({ id: 'Microsoft.ReactNative', version: nugetVersion, hasProps: false, hasTargets: true, }); cppNugetPackages.push({ id: 'Microsoft.ReactNative.Cxx', version: nugetVersion, hasProps: false, hasTargets: true, }); } if (useHermes && rnVersion > 0.64) { cppNugetPackages.push({ id: 'ReactNative.Hermes.Windows', version: '0.7.2', hasProps: false, hasTargets: true, }); } isMonorepo = getConfigProp('isMonorepo', false); monoRoot = getConfigProp('monoRoot') || '..\\..'; templateVars = { rnwPackagePath: isMonorepo ? "".concat(monoRoot.replace(/\//g, '\\'), "\\..\\..\\node_modules\\react-native-windows") : '..\\..\\node_modules\\react-native-windows', useMustache: true, regExpPatternsToRemove: [], name: c.runtime.appId, namespace: namespaceCpp, title: appTitle, namespaceCpp: namespaceCpp, languageIsCpp: language === 'cpp', mainComponentName: mainComponentName, // Visual Studio is very picky about the casing of the guids for projects, project references and the solution // https://www.bing.com/search?q=visual+studio+project+guid+casing&cvid=311a5ad7f9fc41089507b24600d23ee7&FORM=ANAB01&PC=U531 // we therefore have to precariously use the right casing in the right place or risk building in VS breaking. projectGuidLower: "{".concat(projectGuid.toLowerCase(), "}"), projectGuidUpper: "{".concat(projectGuid.toUpperCase(), "}"), // packaging and signing variables: packageGuid: packageGuid, currentUser: currentUser, certificateThumbprint: certificateThumbprint, useExperimentalNuget: experimentalNuGetDependency, nuGetTestFeed: nuGetTestFeed, // cpp template variables useWinUI3: useWinUI3, useHermes: useHermes, xamlNamespace: xamlNamespace, xamlNamespaceCpp: xamlNamespaceCpp, cppNugetPackages: cppNugetPackages, // Development port config devPort: c.runtime.port || 8092, // cs template variables csNugetPackages: csNugetPackages, // autolinking template variables autolinkPropertiesForProps: '', autolinkProjectReferencesForTargets: '', autolinkCsUsingNamespaces: '', autolinkCsReactPackageProviders: '', autolinkCppIncludes: '', autolinkCppPackageProviders: '\n UNREFERENCED_PARAMETER(packageProviders);', hasAdditionalAssets: RNIconsPluginPath && fs.existsSync(RNIconsPluginPath), }; commonMappings = [ // app common mappings { from: path.join(RNWTemplatePath, 'index.windows.bundle'), to: path.join(appFolder, c.runtime.appId, bundleDir, 'index.windows.bundle'), }, { from: path.join(srcPath, projDir, 'MyApp.sln'), to: path.join(appFolder, "".concat(c.runtime.appId, ".sln")), }, { from: path.join(RNWTemplatePath, 'index.windows.bundle'), to: path.join(appFolder, c.runtime.appId, bundleDir, 'index.windows.bundle'), }, { from: path.join(RNWTemplatePath, 'app.json'), to: 'app.json', }, { from: path.join(RNWTemplatePath, 'app.json'), to: path.join(appFolder, c.runtime.appId, bundleDir, 'assets', 'app.json'), }, ]; // Do not override metro inside the project if one already exists if (!fs.existsSync(path.join(c.paths.project.dir, 'metro.config.js'))) { commonMappings.push({ from: path.join(RNWTemplatePath, 'metro.config.js'), to: 'metro.config.js', }); } if (!fs.existsSync(path.join(appFolder, c.runtime.appId, bundleDir, 'assets'))) { fs.mkdirSync(path.join(appFolder, c.runtime.appId, bundleDir, 'assets'), { recursive: true }); } _i = 0, commonMappings_1 = commonMappings; _d.label = 5; case 5: if (!(_i < commonMappings_1.length)) return [3 /*break*/, 8]; mapping = commonMappings_1[_i]; return [4 /*yield*/, generator_common_1.copyAndReplaceWithChangedCallback(mapping.from, c.paths.project.dir, mapping.to, templateVars, options)]; case 6: _d.sent(); _d.label = 7; case 7: _i++; return [3 /*break*/, 5]; case 8: if (!(language === 'cs')) return [3 /*break*/, 13]; csMappings = [ // cs app mappings { from: path.join(srcPath, projDir, 'MyApp.csproj'), to: path.join(appFolder, c.runtime.appId, "".concat(c.runtime.appId, ".csproj")), }, ]; _a = 0, csMappings_1 = csMappings; _d.label = 9; case 9: if (!(_a < csMappings_1.length)) return [3 /*break*/, 12]; mapping = csMappings_1[_a]; return [4 /*yield*/, generator_common_1.copyAndReplaceWithChangedCallback(mapping.from, c.paths.project.dir, mapping.to, templateVars, options)]; case 10: _d.sent(); _d.label = 11; case 11: _a++; return [3 /*break*/, 9]; case 12: return [3 /*break*/, 17]; case 13: cppMappings = [ // cpp app mappings { from: path.join(srcPath, projDir, 'MyApp.vcxproj'), to: path.join(appFolder, c.runtime.appId, "".concat(c.runtime.appId, ".vcxproj")), }, { from: path.join(srcPath, projDir, 'MyApp.vcxproj.filters'), to: path.join(appFolder, c.runtime.appId, "".concat(c.runtime.appId, ".vcxproj.filters")), }, { from: path.join(srcPath, projDir, 'packages.config'), to: path.join(appFolder, c.runtime.appId, 'packages.config'), }, ]; _b = 0, cppMappings_1 = cppMappings; _d.label = 14; case 14: if (!(_b < cppMappings_1.length)) return [3 /*break*/, 17]; mapping = cppMappings_1[_b]; return [4 /*yield*/, generator_common_1.copyAndReplaceWithChangedCallback(mapping.from, c.paths.project.dir, mapping.to, templateVars, options)]; case 15: _d.sent(); _d.label = 16; case 16: _b++; return [3 /*break*/, 14]; case 17: if (!(options.experimentalNuGetDependency || rnVersion > 0.64)) return [3 /*break*/, 21]; if (!fs.existsSync(path.join(sharedPath, projDir))) return [3 /*break*/, 21]; sharedProjMappings = []; sharedProjMappings.push({ from: path.join(sharedPath, projDir, 'NuGet.Config'), to: path.join(appFolder, 'NuGet.Config'), }); if (fs.existsSync(path.join(sharedPath, projDir, 'ExperimentalFeatures.props'))) { sharedProjMappings.push({ from: path.join(sharedPath, projDir, 'ExperimentalFeatures.props'), to: path.join(appFolder, 'ExperimentalFeatures.props'), }); } _c = 0, sharedProjMappings_1 = sharedProjMappings; _d.label = 18; case 18: if (!(_c < sharedProjMappings_1.length)) return [3 /*break*/, 21]; mapping = sharedProjMappings_1[_c]; return [4 /*yield*/, generator_common_1.copyAndReplaceWithChangedCallback(mapping.from, c.paths.project.dir, mapping.to, templateVars, options)]; case 19: _d.sent(); _d.label = 20; case 20: _c++; return [3 /*break*/, 18]; case 21: // Firstly attempt to copy assets specified in project, if user has none specified use default from renative return [4 /*yield*/, copyAssetsFolder(c.runtime.appId)]; case 22: // Firstly attempt to copy assets specified in project, if user has none specified use default from renative _d.sent(); // shared assets if (fs.existsSync(path.join(sharedPath, 'assets'))) { copyFolderContentsRecursiveSync(path.join(sharedPath, 'assets'), path.join(appFolder, c.runtime.appId, 'Assets'), true, false, // Must not override, project defined assets used, if new ones are added later on - rebuild will cover it true); } appFolderFull = getAppFolder(); // react native vector icons fonts // Only copy the files if the plugin is added to the project, aka plugin dir exists if (RNIconsPluginPath && fs.existsSync(RNIconsPluginPath)) { // Default React Native Windows Debug apps use this location copyFolderContentsRecursive(RNIconsPluginPath, path.join(appFolderFull, c.runtime.appId, 'Assets')); // Default React Native Windows Release apps use this location copyFolderContentsRecursive(RNIconsPluginPath, path.join(appFolderFull, c.runtime.appId, 'Bundle', 'assets')); glyphmapsDir = path.join(appFolderFull, c.runtime.appId, 'Assets', 'node_modules', 'react-native-vector-icons', 'glyphmaps'); if (!fs.existsSync(glyphmapsDir)) { fs.mkdirSync(glyphmapsDir, { recursive: true }); } RNIconsGlyphmapsPluginPath = path.join(path.dirname(require.resolve('react-native-vector-icons/package.json', { paths: [c.paths.project.dir], })), 'glyphmaps'); copyFolderContentsRecursive(RNIconsGlyphmapsPluginPath, glyphmapsDir); } if (!fs.existsSync(path.join(sharedPath, 'src'))) return [3 /*break*/, 24]; return [4 /*yield*/, generator_common_1.copyAndReplaceAll(path.join(sharedPath, 'src'), c.paths.project.dir, path.join(appFolder, c.runtime.appId), templateVars, options)]; case 23: _d.sent(); _d.label = 24; case 24: if (!fs.existsSync(path.join(srcPath, 'src'))) return [3 /*break*/, 26]; return [4 /*yield*/, generator_common_1.copyAndReplaceAll(path.join(srcPath, 'src'), c.paths.project.dir, path.join(appFolder, c.runtime.appId), templateVars, options)]; case 25: _d.sent(); _d.label = 26; case 26: return [2 /*return*/]; } }); }); } exports.copyProjectTemplateAndReplace = copyProjectTemplateAndReplace; function toCppNamespace(namespace) { return namespace.replace(/\./g, '::'); } //# sourceMappingURL=copyTemplate.js.map