Create an interactive React Native template

Create quick and easy dynamic templates for your React Native apps with the help of this guide. Read along to find out on how to create this template!
3 min read
Aylin Gokalp
Create an interactive React Native template

This is a guide on how to create a simple template for your future React Native apps while letting the user add and/or drop some of its features.

You can easily use a template to create your app with the React Native cli, for example using react-native-community's Typescript template:

npx react-native init MyApp --template react-native-template-typescript

To create a custom static template, create an app with all the features you need (eg: setup Typescript, some essential libraries or other details).

Then move everything inside a folder named template, this will define the basis of your template.

Next to the template folder create a script named: template.config.js:

module.exports = {
  placeholderName: 'ReactNativeTemplate',
  templateDir: './template'
};
  • placeholderName can be anything, it will temporarily be the name of the project and will be replaced by the name of the app when you init a new project with the React Native cli
  • templateDir is the path to the folder we created that contains the custom template
 _ template/
|  |_ src
|  |_ ios
|  |_ android
|  |_ ...
|
|_ template.config.js

That's it for a static template !

To test this:

  • locally
npx react-native init <app-name> --template file://<absolute-path-to-template>
  • if you push to Github
npx react-native init <app-name> --template https://github.com/<template-url>
  • if you publish to NPM
npx react-native init <app-name> --template <npm-lib-name>

Now, to make this template a bit more dynamic...

We will need install the inquirer package and with it, query the user on various topics.

npm install inquirer

To do so, modify your template.config.js :

module.exports = {
  placeholderName: 'ReactNativeTemplate',
  templateDir: './template',
  postInitScript: './scripts/postInitScript.ts',
};

The postInitScript file is executed after the template's initialisation and before the dependencies are installed.

Add a new scripts/postInitScript.ts file, this will contain everything we need to query the user.

In this file we need to indicate that we will use a Typescript to execute the script:

#!/usr/bin/env ts-node
If you prefer using Javascript, replace ts-node with node

First, start by setting up the spinner to match the React Native cli look:

#!/usr/bin/env ts-node
import ora from 'ora';

const spinner = ora('This is the post-init script');

new Promise((resolve) => {
  spinner.start();
  
  // do something
  
}).then(() => {
  spinner.succeed();
}).catch((error) => {
  spinner.fail(error);
  throw new Error('Something went wrong during the post init script execution');
});

Here we create a spinner using ora and control its state during the execution of our script.

Let's imagine we need to ask the user if they need to have a specific library setup, eg: React Query to handle queries like a pro

import inquirer from 'inquirer';

const QUESTIONS: inquirer.QuestionCollection<{ libraries: string[] }> = [
  {
    name: "reactQuery",
    "type": "confirm",
    default: false,
    "message": "Do you need react-query ?"
  }
];

const inquire = (callback: () => void) => inquirer.prompt(QUESTIONS)
  .then((answers) => {
    console.log("answers", answers)
    
    // do something
    
    callback();
  });

export {
  inquire
}
Import this function in your `postInitScript` file and use it after the spinner starts

With inquirer you can easily query the user, there are different types of prompts (eg: multiple choices, yes/no, text, ...). This will simply prompt the user to answer yes or no for the question  to install react-query .

When the promise successfully resolves (when the user has answered the question correctly and not exited the script), you can act on this answer.

const inquire = (callback: () => void) => inquirer.prompt(QUESTIONS)
  .then((answers) => {
    console.log("answers", answers)
    
    if(answers.reactQuery) {
      console.log("react-query installed")
    }
    
    callback();
  });

Then we can add the new dependency inside the template's package.json file:

const inquire = (callback: () => void) => inquirer.prompt(QUESTIONS)
  .then((answers) => {
    if(answers.reactQuery) {
      // read current file
      const packageJsonContent = fs.readFileSync(PACKAGE_JSON_PATH, { encoding: 'utf8' });
      const projectPackageJson = JSON.parse(packageJsonContent);
      
      // add new item to current dependencies
      const newPackageJson = {
        ...projectPackageJson,
        dependencies: {
          ...projectPackageJson.dependencies,
          'react-query': '^3.34.19'
        }
      };
      
      // write changes to file
      fs.writeFileSync(PACKAGE_JSON_PATH, JSON.stringify(newPackageJson, null, 2) + os.EOL);
    }
    
    callback();
  });

Since the dependencies were not installed yet at this stage, we can just add the new library inside the template/package.json file.

When the post-init script resolves, the cli will continue on to install the dependencies and finish seting-up the new app.

Read the complete code here.

You can now modify the template however you want !

Book a React training!