Skip to content

Commit 3f0adfe

Browse files
author
Ives van Hoorne
committed
Update docs
1 parent a0e2442 commit 3f0adfe

File tree

8 files changed

+186
-59
lines changed

8 files changed

+186
-59
lines changed

packages/react-sandpack/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ compiled
22
storybook-static
33
.rpt2_cache
44
dist
5+
docs

packages/react-sandpack/src/components/SandpackProvider/SandpackProvider.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { Broadcast } from 'react-broadcast';
3-
import { Manager } from 'sandpack';
3+
import { Manager, generatePackageJSON } from 'sandpack';
44
import { listen } from 'codesandbox-api';
55

66
import { IFile, IFiles, IManagerState } from '../../types';
@@ -22,7 +22,7 @@ export interface Props {
2222
};
2323
width?: number | string;
2424
height?: number | string;
25-
sandboxUrl: string;
25+
bundlerURL?: string;
2626
skipEval: boolean;
2727
}
2828

@@ -31,7 +31,6 @@ export default class SandpackProvider extends React.PureComponent<
3131
State
3232
> {
3333
static defaultProps = {
34-
sandboxUrl: 'http://localhost:3001',
3534
skipEval: false,
3635
};
3736

@@ -104,11 +103,13 @@ export default class SandpackProvider extends React.PureComponent<
104103
setupFrame = (el: HTMLIFrameElement) => {
105104
this.manager = new Manager(
106105
el,
107-
this.createMissingPackageJSON(
108-
this.props.files,
109-
this.props.dependencies,
110-
this.props.entry
111-
),
106+
{
107+
files: generatePackageJSON(
108+
this.props.files,
109+
this.props.dependencies,
110+
this.props.entry
111+
),
112+
},
112113
{
113114
skipEval: this.props.skipEval,
114115
}
@@ -123,7 +124,7 @@ export default class SandpackProvider extends React.PureComponent<
123124
this.setState({ files });
124125

125126
if (this.manager) {
126-
this.manager.sendCode(files);
127+
this.manager.updatePreview({ files });
127128
}
128129
};
129130

@@ -165,7 +166,7 @@ export default class SandpackProvider extends React.PureComponent<
165166
openFile: this.openFile,
166167
browserFrame: iframe,
167168
updateFiles: this.updateFiles,
168-
sandboxUrl: this.props.sandboxUrl,
169+
bundlerURL: this.manager ? this.manager.bundlerURL : undefined,
169170
}}
170171
>
171172
<div className="sandpack">
@@ -182,7 +183,7 @@ export default class SandpackProvider extends React.PureComponent<
182183
position: 'absolute',
183184
visibility: 'hidden',
184185
}}
185-
src={this.props.sandboxUrl}
186+
src={this.props.bundlerURL}
186187
/>
187188
{children}
188189
</div>

packages/sandpack/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ compiled
22
storybook-static
33
.rpt2_cache
44
dist
5+
docs

packages/sandpack/README.md

Lines changed: 79 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,134 @@
11
# Sandpack
22

3-
A bundler that completely works in the browser, utilizing browser APIs.
3+
A bundler that completely works in the browser and takes advantage of it.
44

55
## Why?
66

77
Online code playgrounds are getting more popular: they provide an easy way to play with code without installation. Until a year ago it was very hard to play with bigger web applications in the browser; there was no bundler that was comparable with local bundlers and worked in the browser.
88

9-
CodeSandbox came along, and still had a pretty basic bundler. However, as CodeSandbox got more popular its bundler got more advanced. Nowadays the bundler has comparable feature parity with Webpack, and it would be a shame if others couldn't use the functionality.
9+
CodeSandbox came along, and still had a pretty basic bundler. However, as CodeSandbox got more popular its bundler got more advanced. Nowadays the bundler is used for all kinds of bigger web projects, and it would be a shame if others couldn't use the functionality.
1010

11-
This library acts as an interface with the bundler of CodeSandbox. It allows you to run any code on a web page, from Vue projects to React projects. With everything that CodeSandbox supports as well.
11+
This library acts as an interface with the bundler of CodeSandbox. It allows you to run any code on a web page, from Vue projects to React projects to Parcel projects. With everything that CodeSandbox supports as well.
1212

13-
## So what can the bundler do?
13+
## So what can this bundler do?
1414

15-
This is a list of features that the bundler supports, the list may be outdated.
15+
This is a list of features that the bundler supports out of the box, the list may be outdated.
1616

17-
1. Hot Module Reloading API (`module.hot`)
18-
2. npm dependencies
19-
3. Supports most common transpilers (vue, babel, typescript, css)
20-
4. Friendly error overlay
21-
5. Parallel transpiling
22-
6. On-demand transpiler loading
17+
1. Hot Module Reloading API (`module.hot`)
18+
2. npm dependencies
19+
3. Most common transpilers (vue, babel, typescript, css, etc...)
20+
4. Parallel transpiling
21+
5. On-demand transpiler loading
22+
6. Webpack loader syntax (`!raw-loader!./test.js`)
23+
7. Friendly error overlay (using `create-react-app` overlay)
24+
8. Transpilation result caching
2325

2426
## Example usage
2527

26-
There are multiple ways to use the bundler. We provided two ways, but we're open to PRs to extend ways to use this!
28+
This repo serves as an interface to communicate with the bundler. The bundler itself is hosted on `sandpack-{version}.codesandbox.io` and is heavily cached by a CDN. We also included the necessary files under `bundler` if you want to host the bundler yourself.
2729

2830
### Using the Manager
2931

30-
The Manager is a plain JavaScript implementation, you can use it by importing Manager.
32+
The Manager is a class implementation, you can use it by importing Manager.
3133

3234
```js
33-
import { Manager } from 'codesandbox-playground';
35+
import { Manager } from 'sandpack';
3436

35-
// Let's say you want to show the preview on #preview
36-
const m = new Manager(
37+
// There are two ways of initializing a preview, you can give it either an iframe element or a selector of an element to create an iframe on.
38+
const manager = new Manager(
3739
'#preview',
3840
{
3941
files: {
4042
'/index.js': {
4143
code: `console.log(require('uuid'))`,
4244
},
4345
},
46+
entry: '/index.js',
4447
dependencies: {
4548
uuid: 'latest',
4649
},
47-
entry: '/index.js',
48-
} /* you can give a third argument with extra options, described at the bottom */
50+
} /* We support a third parameter for advanced options, you can find more info in the bottom */
4951
);
5052

51-
// This will show the preview on the #preview element, you can now send new code
52-
// by calling 'sendCode(files, dependencies, entry)'. We will automatically determine
53-
// how to hot update the preview.
54-
m.sendCode(
55-
{
53+
// When you make a change you can just run `updatePreview`, we'll automatically discover
54+
// which files have changed and hot reload them.
55+
manager.updatePreview({
56+
files: {
5657
'/index.js': {
57-
code: `console.log('other code')`,
58+
code: `console.log('New Text!')`,
59+
},
60+
entry: '/index.js',
61+
dependencies: {
62+
uuid: 'latest',
5863
},
5964
},
65+
});
66+
```
67+
68+
If you specify a `package.json` in the list of files we will use that as source of truth instead, we infer `dependencies` and `entry` from it:
69+
70+
```js
71+
// We infer dependencies and the entry point from package.json
72+
const PACKAGE_JSON_CODE = JSON.stringify(
6073
{
61-
uuid: 'latest',
74+
title: 'test',
75+
main: 'index.js',
76+
dependencies: {
77+
uuid: 'latest',
78+
},
6279
},
63-
'/index.js'
80+
null,
81+
2
6482
);
83+
84+
// Give it either a selector or an iframe element as first argument, the second arguments are the files
85+
const manager = new Manager('#preview', {
86+
files: {
87+
'/index.js': {
88+
code: `console.log(require('uuid'))`,
89+
},
90+
'/package.json': {
91+
code: PACKAGE_JSON_CODE,
92+
},
93+
},
94+
});
6595
```
6696

6797
### As a React Component
6898

69-
We included a React component you can use, the implementation is fairly simple.
99+
We built another library called `react-sandpack` for usage with `sandpack`. This library provides basic React components for editors, including `FileExplorer`, `CodeEditor` and `BrowserPreview`. This serves as a library that makes it easier to build embeddable or full blown online code editors.
100+
101+
An example implementation:
70102

71103
```jsx
72-
import Preview from 'codesandbox-playground/dist/components/Preview';
104+
import React from 'react';
105+
import { render } from 'react-dom';
106+
import {
107+
FileExplorer,
108+
CodeMirror,
109+
BrowserPreview,
110+
SandpackProvider,
111+
} from 'react-sandpack';
73112

74113
const files = {
75114
'/index.js': {
76-
code: `
77-
console.log('hey')
78-
`,
115+
code: "document.body.innerHTML = `<div>${require('uuid')}</div>`",
79116
},
80117
};
81118

82119
const dependencies = {
83-
react: 'latest',
120+
uuid: 'latest',
84121
};
85122

86-
export default () => <Preview files={files} dependencies={dependencies} entry="/index.js" />;
123+
const App = () => (
124+
<SandpackProvider files={files} dependencies={dependencies} entry="/index.js">
125+
<div style={{ display: 'flex', width: '100%', height: '100%' }}>
126+
<FileExplorer style={{ width: 300 }} />
127+
<CodeMirror style={{ flex: 1 }} />
128+
<BrowserPreview style={{ flex: 1 }} />
129+
</div>
130+
</SandpackProvider>
131+
);
87132
```
88133

89-
We will automatically hot update the preview as the props update.
134+
The above code will render a File Explorer, a working code editor and a preview with browser navigation. For more info about `react-sandpack` you can go here: https://github.com/CompuIves/codesandbox-client/tree/master/packages/react-sandpack.

packages/sandpack/src/manager/index.ts

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,32 @@
1+
/// <reference types="node" />
12
import { dispatch, listen, registerFrame } from 'codesandbox-api';
3+
import generatePackageJSON from '../utils/generate-package-json';
4+
5+
const version = require('../../package.json').version;
26

37
export interface IManagerOptions {
4-
sandboxUrl?: string;
8+
/**
9+
* Location of the bundler
10+
*/
11+
bundlerURL?: string;
512
width?: string;
613
height?: string;
14+
/**
15+
* What template we use, if not defined we infer the template from the dependencies or files.
16+
*/
717
template?: string;
18+
/**
19+
* If we should skip evaluation.
20+
*/
821
skipEval?: boolean;
922
}
1023

24+
export interface IFile {
25+
code: string;
26+
}
27+
1128
export interface IFiles {
12-
[path: string]: {
13-
code: string;
14-
};
29+
[path: string]: IFile;
1530
}
1631

1732
export interface IModules {
@@ -25,23 +40,34 @@ export interface IDependencies {
2540
[depName: string]: string;
2641
}
2742

43+
export type ISandboxInfo = {
44+
files: IFiles;
45+
dependencies?: IDependencies;
46+
entry?: string;
47+
template?: string;
48+
};
49+
50+
const BUNDLER_URL = `https://sandpack-${version}.codesandbox.io`;
51+
2852
export default class PreviewManager {
2953
selector: string | undefined;
3054
element: Element;
3155
iframe: HTMLIFrameElement;
3256
options: IManagerOptions;
3357
listener?: Function;
3458
skipEval: boolean;
59+
bundlerURL: string;
3560

36-
files: IFiles;
61+
sandboxInfo: ISandboxInfo;
3762

3863
constructor(
3964
selector: string | HTMLIFrameElement,
40-
files: IFiles,
65+
sandboxInfo: ISandboxInfo,
4166
options: IManagerOptions = {}
4267
) {
4368
this.options = options;
44-
this.files = files;
69+
this.sandboxInfo = sandboxInfo;
70+
this.bundlerURL = options.bundlerURL || BUNDLER_URL;
4571

4672
if (typeof selector === 'string') {
4773
this.selector = selector;
@@ -67,7 +93,7 @@ export default class PreviewManager {
6793
if (this.iframe) {
6894
registerFrame(this.iframe.contentWindow);
6995

70-
this.sendCode(this.files);
96+
this.updatePreview();
7197
}
7298
break;
7399
}
@@ -78,8 +104,10 @@ export default class PreviewManager {
78104
});
79105
}
80106

81-
sendCode(files: IFiles) {
82-
this.files = files;
107+
updatePreview(sandboxInfo = this.sandboxInfo) {
108+
this.sandboxInfo = sandboxInfo;
109+
110+
const files = this.getFiles();
83111

84112
const modules: IModules = Object.keys(files).reduce(
85113
(prev, next) => ({
@@ -104,9 +132,22 @@ export default class PreviewManager {
104132
});
105133
}
106134

135+
private getFiles() {
136+
const { sandboxInfo } = this;
137+
138+
if (sandboxInfo.files['/package.json'] === undefined) {
139+
return generatePackageJSON(
140+
sandboxInfo.files,
141+
sandboxInfo.dependencies,
142+
sandboxInfo.entry
143+
);
144+
}
145+
146+
return this.sandboxInfo.files;
147+
}
148+
107149
private initializeElement() {
108-
this.iframe.src =
109-
this.options.sandboxUrl || 'https://sandbox.codesandbox.io';
150+
this.iframe.src = this.bundlerURL;
110151
this.iframe.style.border = '0';
111152
this.iframe.style.width = this.options.width || '100%';
112153
this.iframe.style.height = this.options.height || '100%';

packages/sandpack/src/sandpack.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import Manager from './manager/index';
2+
import generatePackageJSON from './utils/generate-package-json';
23

3-
export { Manager };
4+
export { Manager, generatePackageJSON };

0 commit comments

Comments
 (0)