-
Notifications
You must be signed in to change notification settings - Fork 154
Refactor project types & add Next.js #292
Changes from 7 commits
3653634
dd5e77e
91a20c7
6ae6be3
aba6966
b5ca5d1
e16204d
030b40c
5465689
470ec2e
e91b706
c7fbb21
a5f212d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ import styled from 'styled-components'; | |
|
||
import reactIconSrc from '../../assets/images/react-icon.svg'; | ||
import gatsbyIconSrc from '../../assets/images/gatsby_small.png'; | ||
import nextjsIconSrc from '../../assets/images/nextjs.svg'; | ||
|
||
import FormField from '../FormField'; | ||
import ProjectIconSelection from '../ProjectIconSelection'; | ||
|
@@ -79,6 +80,7 @@ class MainPane extends PureComponent<Props> { | |
isFocused={activeField === 'projectType'} | ||
> | ||
<ProjectTypeTogglesWrapper> | ||
{/* Todo: Make it easier to add new flows - e.g. map over an array to generate the UI*/} | ||
<ButtonWithIcon | ||
showStroke={projectType === 'create-react-app'} | ||
icon={<ReactIcon src={reactIconSrc} />} | ||
|
@@ -96,6 +98,14 @@ class MainPane extends PureComponent<Props> { | |
> | ||
Gatsby | ||
</ButtonWithIcon> | ||
<Spacer inline size={10} /> | ||
<ButtonWithIcon | ||
showStroke={projectType === 'nextjs'} | ||
icon={<GatsbyIcon src={nextjsIconSrc} />} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think since <IconImage width={'...'} height={'...'} src={...} /> const IconImage = styled.img`
width: ${props => props.width || '32px'};
height: ${props => props.height || '32px'};
`; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, good catch. That was my mistake I should have created a |
||
onClick={() => this.updateProjectType('nextjs')} | ||
> | ||
Next.js | ||
</ButtonWithIcon> | ||
</ProjectTypeTogglesWrapper> | ||
</FormField> | ||
</FadeIn> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
// app-wide settings (no user changable settings here) | ||
module.exports = { | ||
PACKAGE_MANAGER: 'yarn', | ||
// Enable logging, if enabled all terminal responses are visible in the console (useful for debugging) | ||
LOGGING: true, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// project type configuration | ||
// used for | ||
// - create project command args | ||
// - devServer name mapping | ||
// | ||
export default { | ||
'create-react-app': { | ||
devServer: { | ||
taskName: 'start', | ||
args: ['run', 'start'], | ||
env: { | ||
PORT: '$port', | ||
}, | ||
}, | ||
create: { | ||
// not sure if we need that nesting but I think there could be more to configure | ||
args: projectPath => [ | ||
// used for project creation previous getBuildInstructions | ||
'create-react-app', | ||
projectPath, | ||
], | ||
}, | ||
}, | ||
gatsby: { | ||
devServer: { | ||
taskName: 'develop', | ||
// gatsby needs -p instead of env for port changing | ||
args: ['run', 'develop', '-p', '$port'], | ||
}, | ||
create: { | ||
// not sure if we need that nesting but I think there could be more to configure | ||
args: projectPath => [ | ||
// used for project creation previous getBuildInstructions | ||
'gatsby', | ||
'new', | ||
projectPath, // todo replace later with config variables like $projectPath - so we can remove the function. Also check if it's getting complicated. | ||
], | ||
}, | ||
}, | ||
nextjs: { | ||
devServer: { | ||
taskName: 'dev', | ||
args: ['run', 'dev', '-p', '$port'], | ||
}, | ||
create: { | ||
// not sure if we need that nesting but I think there could be more to configure | ||
args: projectPath => [ | ||
// used for project creation previous getBuildInstructions | ||
'github:awolf81/create-next-app', // later will be 'create-next-app' --> issue not filed yet | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps update the comment for |
||
projectPath, | ||
], | ||
}, | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,7 @@ import { | |
CLEAR_CONSOLE, | ||
RESET_ALL_STATE, | ||
} from '../actions'; | ||
import projectConfigs from '../config/project-types'; | ||
|
||
import type { Action } from 'redux'; | ||
import type { Task, ProjectType } from '../types'; | ||
|
@@ -222,6 +223,10 @@ export default (state: State = initialState, action: Action = {}) => { | |
// | ||
// | ||
// Helpers | ||
export const devServerTaskNames: Array<string> = Object.keys( | ||
projectConfigs | ||
).map(projectType => projectConfigs[projectType].devServer.taskName); | ||
|
||
export const getTaskDescription = (name: string) => { | ||
// NOTE: This information is currently derivable, and it's bad to store | ||
// derivable data in the reducer... but, I expect soon this info will be | ||
|
@@ -251,7 +256,7 @@ export const getTaskDescription = (name: string) => { | |
|
||
export const isDevServerTask = (name: string) => | ||
// Gatsby and create-react-app use different names for the same task. | ||
name === 'start' || name === 'develop'; | ||
devServerTaskNames.indexOf(name) !== -1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: add next.js to comment
Also any reason not to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you're right. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps “Each framework uses a different name for the task that starts the development server”? That way, it doesn’t have to be changed for each new framework. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @j-f1 Even better :) |
||
|
||
// https://docs.npmjs.com/misc/scripts | ||
const preExistingTasks = [ | ||
|
@@ -291,7 +296,7 @@ const getTaskType = name => { | |
// For a dev server, "running" is a successful status - it means there are | ||
// no errors - while for a short-term task, "running" is essentially the same | ||
// as "loading", it's a yellow-light kind of thing. | ||
const sustainedTasks = ['start', 'develop']; | ||
const sustainedTasks = devServerTaskNames; // We could have other tasks we could add - for now we also could use devServerTaskNames directly | ||
|
||
return sustainedTasks.includes(name) ? 'sustained' : 'short-term'; | ||
}; | ||
|
@@ -370,16 +375,10 @@ export const getDevServerTaskForProjectId = ( | |
projectType: ProjectType, | ||
} | ||
) => { | ||
switch (props.projectType) { | ||
case 'create-react-app': { | ||
return state.tasks[props.projectId].start; | ||
} | ||
|
||
case 'gatsby': { | ||
return state.tasks[props.projectId].develop; | ||
} | ||
|
||
default: | ||
throw new Error('Unrecognized project type: ' + props.projectType); | ||
const config = projectConfigs[props.projectType]; | ||
const { taskName } = config.devServer; | ||
if (!config) { | ||
throw new Error('Unrecognized project type: ' + props.projectType); | ||
} | ||
return state.tasks[props.projectId][taskName]; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ import { | |
receiveDataFromTaskExecution, | ||
loadDependencyInfoFromDisk, | ||
} from '../actions'; | ||
import projectConfigs from '../config/project-types'; | ||
import { getProjectById } from '../reducers/projects.reducer'; | ||
import { getPathForProjectId } from '../reducers/paths.reducer'; | ||
import { isDevServerTask } from '../reducers/tasks.reducer'; | ||
|
@@ -25,11 +26,17 @@ import { | |
getBaseProjectEnvironment, | ||
PACKAGE_MANAGER_CMD, | ||
} from '../services/platform.service'; | ||
import { processLogger } from '../services/process-logger.service'; | ||
|
||
import type { Action } from 'redux'; | ||
import type { Saga } from 'redux-saga'; | ||
import type { Task, ProjectType } from '../types'; | ||
|
||
// Mapping type for config template variables '$port' | ||
export type VariableMap = { | ||
$port: string, | ||
}; | ||
|
||
const chalk = new chalkRaw.constructor({ level: 3 }); | ||
|
||
export function* launchDevServer({ task }: Action): Saga<void> { | ||
|
@@ -57,6 +64,8 @@ export function* launchDevServer({ task }: Action): Saga<void> { | |
} | ||
); | ||
|
||
processLogger(child, 'DEVSERVER'); | ||
|
||
// Now that we have a port/processId for the server, attach it to | ||
// the task. The port is used for opening the app, the pid is used | ||
// to kill the process | ||
|
@@ -181,6 +190,8 @@ export function* taskRun({ task }: Action): Saga<void> { | |
} | ||
); | ||
|
||
processLogger(child, 'TASK'); | ||
|
||
// TODO: Does the renderer process still need to know about the child | ||
// processId? | ||
yield put(attachTaskMetadata(task, child.pid)); | ||
|
@@ -249,6 +260,8 @@ export function* taskRun({ task }: Action): Saga<void> { | |
} | ||
); | ||
|
||
processLogger(installProcess, 'EJECT_INSTALL'); | ||
|
||
// `waitForChildProcessToComplete` waits for proper exit before moving on | ||
// otherwise the next tasks (UI related) run too early before `yarn install` | ||
// is finished | ||
|
@@ -349,27 +362,61 @@ const createStdioChannel = ( | |
}); | ||
}; | ||
|
||
export const substituteConfigVariables = ( | ||
AWolf81 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
configObject: any, | ||
variableMap: VariableMap | ||
) => { | ||
// e.g. $port inside args will be replaced with variable reference from variabeMap obj. {$port: port} | ||
return Object.keys(configObject).reduce( | ||
(config, key) => { | ||
if (config[key] instanceof Array) { | ||
// replace $port inside args array | ||
config[key] = config[key].map(arg => variableMap[arg] || arg); | ||
} else { | ||
// check config[key] e.g. is {env: { PORT: '$port'} } | ||
if (config[key] instanceof Object) { | ||
// config[key] = {PORT: '$port'}, key = 'env' | ||
config[key] = Object.keys(config[key]).reduce( | ||
(newObj, nestedKey) => { | ||
// use replacement value if available | ||
newObj[nestedKey] = | ||
variableMap[newObj[nestedKey]] || newObj[nestedKey]; | ||
return newObj; | ||
}, | ||
{ ...config[key] } | ||
); | ||
} | ||
} | ||
// todo: add top level substiution - not used yet but maybe needed later e.g. { env: $port } won't be replaced. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: typo ( |
||
// Bad example but just to have it as reminder. | ||
return config; | ||
}, | ||
{ ...configObject } | ||
); | ||
}; | ||
|
||
export const getDevServerCommand = ( | ||
task: Task, | ||
projectType: ProjectType, | ||
port: string | ||
) => { | ||
switch (projectType) { | ||
case 'create-react-app': | ||
return { | ||
args: ['run', task.name], | ||
env: { | ||
PORT: port, | ||
}, | ||
}; | ||
case 'gatsby': | ||
return { | ||
args: ['run', task.name, '-p', port], | ||
env: {}, | ||
}; | ||
default: | ||
throw new Error('Unrecognized project type: ' + projectType); | ||
const config = projectConfigs[projectType]; | ||
|
||
if (!config) { | ||
throw new Error('Unrecognized project type: ' + projectType); | ||
} | ||
|
||
// Substitution is needed as we'd like to have $port as args or in env | ||
// we can use it in either position and it will be subsituted with the port value here | ||
const devServer = substituteConfigVariables(config.devServer, { | ||
// pass every value that is needed in the commands here | ||
$port: port, | ||
}); | ||
|
||
return { | ||
args: devServer.args, | ||
env: devServer.env || {}, | ||
}; | ||
}; | ||
|
||
export const stripUnusableControlCharacters = (text: string) => | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍