Skip to content

Commit 76bae8f

Browse files
author
Pablo P Varela
authored
Include external resources when exporting ZIP (#4843)
1 parent 7bf3f24 commit 76bae8f

File tree

5 files changed

+91
-10
lines changed

5 files changed

+91
-10
lines changed

.all-contributorsrc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,15 @@
15961596
"code",
15971597
"plugin"
15981598
]
1599+
},
1600+
{
1601+
"login": "pablopunk",
1602+
"name": "Pablo Varela",
1603+
"avatar_url": "https://avatars0.githubusercontent.com/u/4324982?v=4",
1604+
"profile": "https://pablo.pink",
1605+
"contributions": [
1606+
"code"
1607+
]
15991608
}
16001609
],
16011610
"contributorsPerLine": 7,

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ Thanks goes to these wonderful people
259259
<tr>
260260
<td align="center"><a href="https://github.com/NinoMaj"><img src="https://avatars0.githubusercontent.com/u/20380632?v=4" width="100px;" alt="Nino"/><br /><sub><b>Nino</b></sub></a><br /><a href="https://github.com/codesandbox/codesandbox-client/commits?author=NinoMaj" title="Documentation">📖</a></td>
261261
<td align="center"><a href="https://saurabhdaware.in/"><img src="https://avatars1.githubusercontent.com/u/30949385?v=4" width="100px;" alt="Saurabh Daware"/><br /><sub><b>Saurabh Daware</b></sub></a><br /><a href="https://github.com/codesandbox/codesandbox-client/commits?author=saurabhdaware" title="Code">💻</a> <a href="#plugin-saurabhdaware" title="Plugin/utility libraries">🔌</a></td>
262+
<td align="center"><a href="https://pablo.pink"><img src="https://avatars0.githubusercontent.com/u/4324982?v=4" width="100px;" alt="Pablo P Varela"/><br /><sub><b>Pablo P Varela</b></sub></a><br /><a href="https://github.com/codesandbox/codesandbox-client/commits?author=pablopunk" title="Code">💻</a></td>
262263
</tr>
263264
</table>
264265

packages/app/src/app/overmind/effects/zip/create-zip/index.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { Directory, Module, Sandbox } from '@codesandbox/common/lib/types';
1313
import { saveAs } from 'file-saver';
1414
import ignore from 'ignore';
1515
import JSZip from 'jszip';
16+
import { injectExternalResources } from 'app/utils/inject-resources-for-export';
1617

1718
export const BLOB_ID = 'blob-url://';
1819

@@ -215,7 +216,16 @@ export async function createZip(
215216
ignorer.add(gitIgnore ? gitIgnore.code : '');
216217
}
217218

218-
const filteredModules = modules.filter(module => {
219+
let modifiedModules = modules;
220+
221+
if (sandbox.externalResources?.length > 0) {
222+
modifiedModules = injectExternalResources(
223+
modules,
224+
sandbox.externalResources
225+
);
226+
}
227+
228+
const filteredModules = modifiedModules.filter(module => {
219229
// Relative path
220230
const path = getModulePath(modules, directories, module.id).substring(1);
221231
return !ignorer.ignores(path);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { Module } from '@codesandbox/common/lib/types';
2+
import {
3+
resourceIsCss,
4+
createExternalCSSLink,
5+
createExternalJSLink,
6+
} from 'sandbox/external-resources';
7+
8+
function isFileHTML(path: string) {
9+
return /\.html$/g.test(path);
10+
}
11+
12+
function addElementToHTMLHead(code: string, resource: string) {
13+
const element: HTMLLinkElement | HTMLScriptElement = resourceIsCss(resource)
14+
? createExternalCSSLink(resource)
15+
: createExternalJSLink(resource);
16+
17+
const newCode = code.replace(/<\/head>/g, `\t${element.outerHTML}\n</head>`);
18+
19+
return newCode;
20+
}
21+
22+
// Returns the modules with the externalResources injected.
23+
// Useful for static exports.
24+
export function injectExternalResources(
25+
modules: Module[],
26+
externalResources: string[]
27+
): Module[] {
28+
const modifiedModules = modules.map(mod => {
29+
const modifiedModule = { ...mod };
30+
31+
if (mod.type === 'file' && isFileHTML(mod.path)) {
32+
externalResources.forEach(resource => {
33+
modifiedModule.code = addElementToHTMLHead(
34+
modifiedModule.code,
35+
resource
36+
);
37+
});
38+
}
39+
40+
return modifiedModule;
41+
});
42+
43+
return modifiedModules;
44+
}

packages/app/src/sandbox/external-resources.ts

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ function getExternalResourcesConcatenation(resources: Array<string>) {
33
}
44
/* eslint-disable no-cond-assign */
55
function clearExternalResources() {
6-
let el = null;
6+
let el: HTMLElement | null = null;
77
// eslint-disable-next-line no-cond-assign
88
while ((el = document.getElementById('external-css'))) {
99
el.remove();
@@ -16,36 +16,53 @@ function clearExternalResources() {
1616
}
1717
/* eslint-enable */
1818

19-
function addCSS(resource: string) {
20-
const head = document.getElementsByTagName('head')[0];
19+
export function createExternalCSSLink(resource: string): HTMLLinkElement {
2120
const link = document.createElement('link');
21+
2222
link.id = 'external-css';
2323
link.rel = 'stylesheet';
2424
link.type = 'text/css';
2525
link.href = resource;
2626
link.media = 'all';
27+
28+
return link;
29+
}
30+
31+
function addCSS(resource: string) {
32+
const head = document.getElementsByTagName('head')[0];
33+
const link = createExternalCSSLink(resource);
34+
2735
head.appendChild(link);
2836

2937
return link;
3038
}
3139

32-
function addJS(resource: string) {
40+
export function createExternalJSLink(resource): HTMLScriptElement {
3341
const script = document.createElement('script');
42+
3443
script.setAttribute('src', resource);
3544
script.async = false;
3645
script.setAttribute('id', 'external-js');
46+
47+
return script;
48+
}
49+
50+
function addJS(resource: string) {
51+
const script = createExternalJSLink(resource);
52+
3753
document.head.appendChild(script);
3854

3955
return script;
4056
}
4157

42-
function addResource(resource: string) {
58+
export function resourceIsCss(resource: string): boolean {
4359
const match = resource.match(/\.([^.]*)$/);
4460

45-
const el =
46-
(match && match[1] === 'css') || resource.includes('fonts.googleapis')
47-
? addCSS(resource)
48-
: addJS(resource);
61+
return (match && match[1] === 'css') || resource.includes('fonts.googleapis');
62+
}
63+
64+
function addResource(resource: string) {
65+
const el = resourceIsCss(resource) ? addCSS(resource) : addJS(resource);
4966

5067
return new Promise(r => {
5168
el.onload = r;

0 commit comments

Comments
 (0)