Skip to content

Commit 9587b97

Browse files
SaraVieiraCompuIves
authored andcommitted
Add support for netlify.toml (codesandbox#1772)
* add support for netlify.toml * small fixes * fix for no config * fix for no config * some fixes * support toml config * fix for function folder not existing * clean function * fix css * move to common
1 parent 53b9932 commit 9587b97

File tree

12 files changed

+140
-11
lines changed

12 files changed

+140
-11
lines changed

packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Elements.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ export const Name = styled.span`
5353
: 'rgba(255, 255, 255, 0.8)'};
5454
font-size: 1rem;
5555
margin-top: 0;
56-
margin-bottom: 0.5rem;
5756
vertical-align: middle;
5857
5958
span {

packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Netlify.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import React, { Component } from 'react';
22
import { inject, observer } from 'mobx-react';
3+
34
import LinkIcon from 'react-icons/lib/fa/external-link';
45
import Cogs from 'react-icons/lib/fa/cogs';
6+
import LightningIcon from 'react-icons/lib/md/flash-on';
57
import NetlifyLogo from 'app/components/NetlifyLogo';
68
import DeploymentIntegration from 'app/components/DeploymentIntegration';
79
import getTemplate from '@codesandbox/common/lib/templates';
810
import { Button } from '@codesandbox/common/lib/components/Button';
11+
import { resolveDirectory } from '@codesandbox/common/lib/sandbox/modules';
12+
import getNetlifyConfig from 'app/utils/getNetlifyConfig';
913
import { WorkspaceInputContainer, WorkspaceSubtitle } from '../../elements';
1014
import {
1115
Deploys,
@@ -17,6 +21,18 @@ import {
1721
ButtonContainer,
1822
} from './Elements';
1923

24+
const getFunctionDir = sandbox => {
25+
try {
26+
return resolveDirectory(
27+
getNetlifyConfig(sandbox).functions,
28+
sandbox.modules,
29+
sandbox.directories
30+
);
31+
} catch (e) {
32+
return [];
33+
}
34+
};
35+
2036
class NetlifyDeployment extends Component {
2137
state = { show: false };
2238

@@ -37,6 +53,11 @@ class NetlifyDeployment extends Component {
3753

3854
const template = getTemplate(editor.currentSandbox.template);
3955
const { show } = this.state;
56+
const functionDirectory = getFunctionDir(editor.currentSandbox);
57+
58+
const functions = editor.currentSandbox.modules.filter(
59+
m => m.directoryShortid === functionDirectory.shortid
60+
);
4061
return (
4162
template.netlify !== false && (
4263
<Wrapper loading={deployment.deploying}>
@@ -77,11 +98,59 @@ class NetlifyDeployment extends Component {
7798
<Deploy key={deployment.netlifySite.uid}>
7899
<Name light>{deployment.netlifySite.name}</Name>
79100
{!deployment.building && <div>Building</div>}
101+
{functions.length ? (
102+
<>
103+
<WorkspaceSubtitle
104+
css={`
105+
padding-left: 0;
106+
`}
107+
>
108+
Functions
109+
</WorkspaceSubtitle>
110+
<section
111+
css={`
112+
display: flex;
113+
margin-bottom: 0.5rem;
114+
`}
115+
>
116+
{functions.map(file => (
117+
<Link
118+
disabled={deployment.building}
119+
href={`${
120+
deployment.netlifySite.url
121+
}/.netlify/functions/${
122+
file.title.split('.js')[0]
123+
}`}
124+
css={`
125+
margin-top: 0;
126+
margin-right: 0.5rem;
127+
`}
128+
target="_blank"
129+
rel="noreferrer noopener"
130+
>
131+
<LightningIcon />
132+
<span>{file.title.split('.js')[0]}</span>
133+
</Link>
134+
))}
135+
</section>
136+
</>
137+
) : null}
138+
139+
<WorkspaceSubtitle
140+
css={`
141+
padding-left: 0;
142+
`}
143+
>
144+
Actions
145+
</WorkspaceSubtitle>
80146
<ButtonContainer>
81147
<Link
82148
disabled={deployment.building}
83149
href={deployment.netlifySite.url}
84150
target="_blank"
151+
css={`
152+
margin-top: 0;
153+
`}
85154
rel="noreferrer noopener"
86155
>
87156
{deployment.building ? (
@@ -100,6 +169,9 @@ class NetlifyDeployment extends Component {
100169
disabled={deployment.building}
101170
href={deployment.netlifyClaimUrl}
102171
target="_blank"
172+
css={`
173+
margin-top: 0;
174+
`}
103175
rel="noreferrer noopener"
104176
>
105177
<span>Claim Site</span>

packages/app/src/app/store/modules/deployment/actions.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { omit } from 'lodash-es';
2-
2+
import getNetlifyConfig from 'app/utils/getNetlifyConfig';
33
import getTemplate from '@codesandbox/common/lib/templates';
44
import pollUntilDone from '../../utils/pollUntilDone';
55

@@ -61,6 +61,11 @@ export async function deployToNetlify({ http, props, state }) {
6161
return 'build';
6262
};
6363

64+
const buildConfig = getNetlifyConfig(sandbox);
65+
// command needs to be passed without the package manager name
66+
const buildCommandFromConfig = (buildConfig.command || '')
67+
.replace('npm run', '')
68+
.replace('yarn ', '');
6469
let id = '';
6570
try {
6671
const { result } = await http.request({
@@ -82,9 +87,9 @@ export async function deployToNetlify({ http, props, state }) {
8287

8388
try {
8489
await http.request({
85-
url: `${NetlifyBaseURL}/${sandboxId}/deploys?siteId=${id}&dist=${
86-
template.distDir
87-
}&buildCommand=${buildCommand(template.name)}`,
90+
url: `${NetlifyBaseURL}/${sandboxId}/deploys?siteId=${id}&dist=${buildConfig.publish ||
91+
template.distDir}&buildCommand=${buildCommandFromConfig ||
92+
buildCommand(template.name)}`,
8893
method: 'POST',
8994
body: file,
9095
headers: {

packages/app/src/app/utils/get-type.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const specialCasesMap = {
99
'package.json': 'npm',
1010
'sandbox.config.json': 'codesandbox',
1111
'now.json': 'now',
12+
'netlify.toml': 'settings',
1213
'readme.md': 'readme',
1314
'contributing.md': 'contributing',
1415
'tsconfig.json': 'typescript',
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { mapKeys } from 'lodash-es';
2+
import toml from 'markty-toml';
3+
4+
export default sandbox => {
5+
const netlifyConfig = sandbox.modules
6+
.filter(
7+
module =>
8+
module.title === 'netlify.toml' && module.directoryShortid == null
9+
)
10+
.map(m => toml(m.code))[0] || { build: {} };
11+
return mapKeys(netlifyConfig.build, (v, k) => k.toLowerCase());
12+
};

packages/common/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"image-extensions": "^1.1.0",
2626
"jsonlint": "^1.6.3",
2727
"lodash": "^4.17.11",
28+
"markty-toml": "^0.0.9",
2829
"memoize-one": "^3.1.1",
2930
"moment": "^2.18.1",
3031
"ot": "^0.0.15",

packages/common/src/templates/configuration/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
21
import packageJSON from './package-json';
32
import prettierRC from './prettierRC';
43
import sandboxConfig from './sandbox';
54
import babelrc from './babelrc';
65
import nowConfig from './now';
6+
import netlifyConfig from './netlify';
77
import angularCli from './angular-cli';
88
import angularJSON from './angular-json';
99
import tsconfig from './tsconfig';
@@ -21,6 +21,7 @@ const configs = {
2121
tsconfig,
2222
customCodeSandbox,
2323
nowConfig,
24+
netlifyConfig,
2425
};
2526

2627
export default configs;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { ConfigurationFile } from '../types';
2+
3+
const config: ConfigurationFile = {
4+
title: 'netlify.toml',
5+
type: 'netlify',
6+
description: 'Configuration for your deployments in netlify.',
7+
moreInfoUrl: 'https://www.netlify.com/docs/netlify-toml-reference/',
8+
9+
getDefaultCode: () => '',
10+
};
11+
12+
export default config;

packages/common/src/templates/configuration/parse.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
21
import { ConfigurationFile } from '../../templates/configuration/types';
3-
2+
import toml from 'markty-toml';
43
import { parse } from 'jsonlint';
54
import { ParsedConfigurationFiles } from '../template';
65
import { Sandbox, Module } from '../../types';
@@ -57,11 +56,25 @@ export default function parseConfigurations(
5756
path,
5857
...getCode(template, module, sandbox, resolveModule, configurationFile),
5958
};
59+
6060
const code = baseObject.code;
6161

6262
if (code) {
6363
try {
64-
const parsed = parse(code);
64+
let parsed;
65+
// it goes here three times and the third time it doesn't have a title but a path
66+
// that took a while ffs
67+
// if toml do it with toml parser
68+
if (
69+
module &&
70+
((module.title && module.title.includes('.toml')) ||
71+
(module.path && module.path.includes('.toml')))
72+
) {
73+
// never throws
74+
parsed = toml(code);
75+
} else {
76+
parsed = parse(code);
77+
}
6578

6679
configurations[configurationFile.type] = {
6780
...baseObject,

packages/common/src/templates/template.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const defaultConfigurations = {
3535
'/.prettierrc': configurations.prettierRC,
3636
'/sandbox.config.json': configurations.sandboxConfig,
3737
'/now.json': configurations.nowConfig,
38+
'/netlify.toml': configurations.netlifyConfig,
3839
};
3940

4041
export type ViewConfig = {

0 commit comments

Comments
 (0)