mirror of
				https://github.com/strapi/strapi.git
				synced 2025-10-31 18:08:11 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			203 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			203 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| const { resolve, join, basename } = require('path');
 | |
| const os = require('os');
 | |
| const fse = require('fs-extra');
 | |
| const ora = require('ora');
 | |
| const ciEnv = require('ci-info');
 | |
| const chalk = require('chalk');
 | |
| 
 | |
| const { generateNewApp } = require('@strapi/generate-new');
 | |
| 
 | |
| const hasYarn = require('./has-yarn');
 | |
| const { runInstall, runApp, initGit } = require('./child-process');
 | |
| const { getStarterPackageInfo, downloadNpmStarter } = require('./fetch-npm-starter');
 | |
| const logger = require('./logger');
 | |
| const stopProcess = require('./stop-process');
 | |
| 
 | |
| /**
 | |
|  * @param  {string} - filePath Path to starter.json file
 | |
|  */
 | |
| function readStarterJson(filePath, starter) {
 | |
|   try {
 | |
|     const data = fse.readFileSync(filePath);
 | |
|     return JSON.parse(data);
 | |
|   } catch (err) {
 | |
|     stopProcess(`Could not find ${chalk.yellow('starter.json')} in ${chalk.yellow(starter)}`);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @param {string} rootPath - Path to the project directory
 | |
|  * @param {string} projectName - Name of the project
 | |
|  * @param {Object} options
 | |
|  * @param {boolean} options.useYarn - Use yarn instead of npm
 | |
|  */
 | |
| async function initPackageJson(rootPath, projectName, { useYarn } = {}) {
 | |
|   const packageManager = useYarn ? 'yarn --cwd' : 'npm run --prefix';
 | |
| 
 | |
|   try {
 | |
|     await fse.writeJson(
 | |
|       join(rootPath, 'package.json'),
 | |
|       {
 | |
|         name: projectName,
 | |
|         private: true,
 | |
|         version: '0.0.0',
 | |
|         scripts: {
 | |
|           'develop:backend': `${packageManager} backend develop`,
 | |
|           'develop:frontend': `wait-on http://localhost:1337/admin && ${packageManager} frontend develop`,
 | |
|           develop: 'cross-env FORCE_COLOR=1 npm-run-all -l -p develop:*',
 | |
|         },
 | |
|         devDependencies: {
 | |
|           'npm-run-all': '4.1.5',
 | |
|           'wait-on': '5.2.1',
 | |
|           'cross-env': '7.0.3',
 | |
|         },
 | |
|       },
 | |
|       {
 | |
|         spaces: 2,
 | |
|       }
 | |
|     );
 | |
|   } catch (err) {
 | |
|     stopProcess(`Failed to create ${chalk.yellow(`package.json`)} in ${chalk.yellow(rootPath)}`);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @param {string} path The directory path for install
 | |
|  * @param {Object} options
 | |
|  * @param {boolean} options.useYarn Use yarn instead of npm
 | |
|  */
 | |
| async function installWithLogs(path, options) {
 | |
|   const installPrefix = chalk.yellow('Installing dependencies:');
 | |
|   const loader = ora(installPrefix).start();
 | |
|   const logInstall = (chunk = '') => {
 | |
|     loader.text = `${installPrefix} ${chunk
 | |
|       .toString()
 | |
|       .split('\n')
 | |
|       .join(' ')}`;
 | |
|   };
 | |
| 
 | |
|   const runner = runInstall(path, options);
 | |
|   runner.stdout.on('data', logInstall);
 | |
|   runner.stderr.on('data', logInstall);
 | |
| 
 | |
|   await runner;
 | |
| 
 | |
|   loader.stop();
 | |
|   console.log(`Dependencies installed ${chalk.green('successfully')}.`);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @param {string} starter The name of the starter as provided by the user
 | |
|  * @param {Object} options
 | |
|  * @param {boolean} options.useYarn Use yarn instead of npm
 | |
|  */
 | |
| async function getStarterInfo(starter, { useYarn } = {}) {
 | |
|   const isLocalStarter = ['./', '../', '/'].some(filePrefix => starter.startsWith(filePrefix));
 | |
| 
 | |
|   let starterPath;
 | |
|   let starterParentPath;
 | |
|   let starterPackageInfo = {};
 | |
| 
 | |
|   if (isLocalStarter) {
 | |
|     // Starter is a local directory
 | |
|     console.log('Installing local starter.');
 | |
|     starterPath = resolve(starter);
 | |
|   } else {
 | |
|     // Starter should be an npm package. Fetch starter info
 | |
|     starterPackageInfo = await getStarterPackageInfo(starter, { useYarn });
 | |
|     console.log(`Installing ${chalk.yellow(starterPackageInfo.name)} starter.`);
 | |
| 
 | |
|     // Download starter repository to a temporary directory
 | |
|     starterParentPath = await fse.mkdtemp(join(os.tmpdir(), 'strapi-'));
 | |
|     starterPath = await downloadNpmStarter(starterPackageInfo, starterParentPath, { useYarn });
 | |
|   }
 | |
| 
 | |
|   return { isLocalStarter, starterPath, starterParentPath, starterPackageInfo };
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @param {Object} projectArgs - The arguments for create a project
 | |
|  * @param {string|null} projectArgs.projectName - The name/path of project
 | |
|  * @param {string|null} projectArgs.starter - The npm package of the starter
 | |
|  * @param {Object} program - Commands for generating new application
 | |
|  */
 | |
| module.exports = async function buildStarter({ projectName, starter }, program) {
 | |
|   const hasYarnInstalled = await hasYarn();
 | |
|   const {
 | |
|     isLocalStarter,
 | |
|     starterPath,
 | |
|     starterParentPath,
 | |
|     starterPackageInfo,
 | |
|   } = await getStarterInfo(starter, { useYarn: hasYarnInstalled });
 | |
| 
 | |
|   // Project directory
 | |
|   const rootPath = resolve(projectName);
 | |
|   const projectBasename = basename(rootPath);
 | |
|   const starterJson = readStarterJson(join(starterPath, 'starter.json'), starter);
 | |
| 
 | |
|   try {
 | |
|     await fse.ensureDir(rootPath);
 | |
|   } catch (error) {
 | |
|     stopProcess(`Failed to create ${chalk.yellow(rootPath)}: ${error.message}`);
 | |
|   }
 | |
| 
 | |
|   // Copy the downloaded frontend folder to the project folder
 | |
|   const frontendPath = join(rootPath, 'frontend');
 | |
| 
 | |
|   try {
 | |
|     await fse.copy(join(starterPath, 'starter'), frontendPath, {
 | |
|       overwrite: true,
 | |
|       recursive: true,
 | |
|     });
 | |
|   } catch (error) {
 | |
|     stopProcess(`Failed to create ${chalk.yellow(frontendPath)}: ${error.message}`);
 | |
|   }
 | |
| 
 | |
|   // Delete the starter directory if it was downloaded
 | |
|   if (!isLocalStarter) {
 | |
|     await fse.remove(starterParentPath);
 | |
|   }
 | |
| 
 | |
|   // Set command options for Strapi app
 | |
|   const generateStrapiAppOptions = {
 | |
|     ...program,
 | |
|     starter: starterPackageInfo.name,
 | |
|     run: false,
 | |
|   };
 | |
|   if (starterJson.template.version) {
 | |
|     generateStrapiAppOptions.template = `${starterJson.template.name}@${starterJson.template.version}`;
 | |
|   } else {
 | |
|     generateStrapiAppOptions.template = starterJson.template.name;
 | |
|   }
 | |
| 
 | |
|   // Create strapi app using the template
 | |
|   await generateNewApp(join(rootPath, 'backend'), generateStrapiAppOptions);
 | |
| 
 | |
|   // Install frontend dependencies
 | |
|   console.log(`Creating Strapi starter frontend at ${chalk.yellow(frontendPath)}.`);
 | |
|   console.log('Installing frontend dependencies');
 | |
|   await installWithLogs(frontendPath, { useYarn: hasYarnInstalled });
 | |
| 
 | |
|   // Setup monorepo
 | |
|   initPackageJson(rootPath, projectBasename, { useYarn: hasYarnInstalled });
 | |
| 
 | |
|   // Add gitignore
 | |
|   try {
 | |
|     const gitignore = join(__dirname, '..', 'resources', 'gitignore');
 | |
|     await fse.copy(gitignore, join(rootPath, '.gitignore'));
 | |
|   } catch (err) {
 | |
|     logger.warn(`Failed to create file: ${chalk.yellow('.gitignore')}`);
 | |
|   }
 | |
| 
 | |
|   await installWithLogs(rootPath, { useYarn: hasYarnInstalled });
 | |
| 
 | |
|   if (!ciEnv.isCI) {
 | |
|     await initGit(rootPath);
 | |
|   }
 | |
| 
 | |
|   console.log(chalk.green('Starting the app'));
 | |
|   await runApp(rootPath, { useYarn: hasYarnInstalled });
 | |
| };
 | 
