Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Nextjs + Redux + React app with opinionated architecture.
const fs = require('fs');
const { execSync } = require('child_process');
if (!process.argv[2]) {
console.log('useage: node create-next-app.js <appname>');
process.exit(1);
}
const rootFolder = process.argv[2];
if (!fs.existsSync(`./${rootFolder}`)) {
fs.mkdirSync(`./${rootFolder}`);
process.chdir(`./${rootFolder}`);
} else {
console.log('Folder already exists');
process.exit(1);
}
/**
* This function creates the .env file for the app
*/
function createEnv() {
console.log('Creating: .env file');
fs.writeFile('./.env', 'NODE_ENV=development', function(err) {
if (err) {
return console.log(err);
}
console.log('Success: .env file written');
});
}
/**
* This function creates all the directories needed to fit the architecture
*/
function setupDirectories() {
fs.mkdirSync('./src');
fs.mkdirSync('./src/state');
fs.mkdirSync('./src/state/example');
fs.mkdirSync('./src/components');
fs.mkdirSync('./pages');
}
/**
* This function creates the redux store with opinionated middleware and devtools
*/
function createStore() {
console.log('Creating: store.js');
fs.writeFile(
'./src/state/store.js',
`import { createStore, combineReducers, compose, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
import example from './example/reducer.js';
const { NODE_ENV } = process.env;
const reducers = {
example
};
let store = null;
export const initStore = (initialState = {}) => {
const reducer = combineReducers(reducers);
if (typeof window === 'undefined') {
store = createStore(reducer, initialState, compose(applyMiddleware(thunk)));
return store;
}
const composeEnhancers = NODE_ENV === 'development' ? composeWithDevTools : compose;
if (!store) {
store = createStore(reducer, initialState, composeEnhancers(applyMiddleware(thunk)));
// set window.store for production debugging purposes
window.store = store;
}
return store;
};`,
function(err) {
if (err) {
return console.log(err);
}
console.log('Success: store.js file written');
}
);
}
/**
* This function creates 3 files, aciton creators, reducer and constants. They work together in harmony.
*/
function createExampleReducer() {
console.log('Creating: Example Reducer');
//Create example constants
console.log('Creating: Example Reducer: Constants');
fs.writeFile('./src/state/example/constants.js', `export const EXAMPLE_ACTION = 'EXAMPLE_ACTION';`, function(err) {
if (err) {
return console.log(err);
}
console.log('Success: Example Reducer: Constants written');
});
//Create axample action creator
console.log('Creating: Example Reducer: Action Creators');
fs.writeFile(
'./src/state/example/actions.js',
`import { EXAMPLE_ACTION } from './constants';
export const exampleAction = (data) => {
return {
type: EXAMPLE_ACTION,
data: data
}
};`,
function(err) {
if (err) {
return console.log(err);
}
console.log('Success: Example Reducer: Action Creators written');
}
);
//Create axample reducer
console.log('Creating: Example Reducer: Reducer');
fs.writeFile(
'./src/state/example/reducer.js',
`import { EXAMPLE_ACTION } from './constants';
const defaultState = {
exampleKey: 'exampleValue'
};
export default (state = defaultState, action) => {
const { type, data } = action;
switch (type) {
case EXAMPLE_ACTION: {
return Object.assign({}, state, {
data
});
}
default:
return state;
}
};`,
function(err) {
if (err) {
return console.log(err);
}
console.log('Success: Example Reducer: Reducer written');
}
);
}
/**
* This function creates an example component
*/
function createExampleComponent() {
console.log('Creating: example component');
fs.writeFile(
'./src/components/example.js',
`import React, { Component } from 'react';
class ExampleComponent extends Component {
render() {
return (
<div>
<h2>Example Component!</h2>
</div>
);
}
}
export default ExampleComponent;`,
function(err) {
if (err) {
return console.log(err);
}
console.log('Success: example component written');
}
);
}
/**
* This function creates the index file in the pages folder that Nextjs uses for routing.
*/
function createPages() {
console.log('Creating: pages');
fs.writeFile(
'./pages/index.js',
`import React, { Component } from 'react';
import withRedux from 'next-redux-wrapper';
import { connect } from 'react-redux';
import ExampleComponent from '../src/components/example';
import { initStore } from '../src/state/store';
class App extends Component {
render() {
return (
<div>
<ExampleComponent />
</div>
);
}
}
export default withRedux(initStore)(App);`,
function(err) {
if (err) {
return console.log(err);
}
console.log('Success: pages written');
}
);
}
/**
* Just a console.log with some instructions to finish off the app.
*/
function logEnding() {
console.log('*******************************');
console.log('*');
console.log('*');
console.log('* Your App is now ready, run:');
console.log('*');
console.log(`* cd ${rootFolder} && npm run dev`);
console.log('*');
console.log('*');
console.log('*******************************');
}
/**
* This modifies the package.json to add Nextjs scripts.
*/
function addScriptsToPackage() {
console.log('Adding scripts to package.json');
var fileName = './package.json';
var file = JSON.parse(fs.readFileSync(fileName, 'utf8'));
file.scripts.dev = 'next';
fs.writeFileSync(fileName, JSON.stringify(file, null, 2));
console.log('Sucess: Scripts added to package.json');
}
/**
* This runs npm install with the packages we need
*/
function npmInstall() {
execSync(
'npm install --save next react react-dom redux react-redux next-redux-wrapper redux-thunk redux-devtools-extension',
{ stdio: 'inherit' }
);
}
/**
* This runs npm init with all defaults
*/
function npmInit() {
execSync('npm init --yes', { stdio: 'inherit' });
}
createEnv();
npmInit();
npmInstall();
setupDirectories();
createStore();
createExampleReducer();
createExampleComponent();
createPages();
addScriptsToPackage();
logEnding();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment