Skip to content

Commit 1c7682e

Browse files
committed
Fix edge case, add benchmarking
1 parent ed7174b commit 1c7682e

File tree

7 files changed

+162
-23
lines changed

7 files changed

+162
-23
lines changed

packages/app/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
"downshift": "^1.0.0-rc.14",
117117
"eslint-plugin-react-hooks": "1.6.0",
118118
"eslint-plugin-vue": "^4.2.2",
119+
"estree-walker": "^1.0.1",
119120
"file-saver": "^1.3.3",
120121
"fontfaceobserver": "^2.0.13",
121122
"fuse.js": "^3.2.1",

packages/app/src/sandbox/eval/manager.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { ParsedConfigurationFiles } from '@codesandbox/common/lib/templates/temp
99
import DependencyNotFoundError from 'sandbox-hooks/errors/dependency-not-found-error';
1010
import ModuleNotFoundError from 'sandbox-hooks/errors/module-not-found-error';
1111

12+
import { generateBenchmarkInterface } from '../utils/benchmark';
1213
import { Module } from './types/module';
1314
import TranspiledModule, {
1415
ChildModule,
@@ -161,6 +162,9 @@ export default class Manager {
161162
if (process.env.NODE_ENV === 'development') {
162163
// eslint-disable-next-line no-console
163164
console.log(this);
165+
166+
// Initialize benchmark logic
167+
getGlobal().Benchmark = generateBenchmarkInterface(this);
164168
}
165169

166170
BrowserFS.configure(
@@ -499,6 +503,10 @@ export default class Manager {
499503
this.getTranspiledModules().map(tModule => tModule.resetCompilation());
500504
}
501505

506+
clearTranspilationCache() {
507+
this.getTranspiledModules().map(tModule => tModule.resetTranspilation());
508+
}
509+
502510
getModules(): Array<Module | ChildModule> {
503511
return values(this.transpiledModules).map(t => t.module);
504512
}

packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/__snapshots__/index.test.ts.snap

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ exports[`convert-esmodule can convert class default exports 1`] = `
44
"Object.defineProperty(exports, \\"__esModule\\", {
55
value: true
66
});
7-
var $csb__default = class A {};
8-
exports.default = $csb__default;
7+
exports.default = A;
8+
class A {}
99
"
1010
`;
1111

1212
exports[`convert-esmodule can convert default exports 1`] = `
1313
"Object.defineProperty(exports, \\"__esModule\\", {
1414
value: true
1515
});
16-
var $csb__default = function test() {};
17-
exports.default = $csb__default;
16+
exports.default = test;
17+
function test() {}
1818
"
1919
`;
2020

@@ -127,4 +127,23 @@ var c = $csb__b.c;
127127
"
128128
`;
129129

130+
exports[`convert-esmodule handles export mutations 1`] = `
131+
"Object.defineProperty(exports, \\"__esModule\\", {
132+
value: true
133+
});
134+
exports.default = test;
135+
function test() {}
136+
exports.default = test = 5;;
137+
"
138+
`;
139+
140+
exports[`convert-esmodule handles export mutations with no named function 1`] = `
141+
"Object.defineProperty(exports, \\"__esModule\\", {
142+
value: true
143+
});
144+
exports.default = $csb__default;
145+
function $csb__default() {}
146+
"
147+
`;
148+
130149
exports[`convert-esmodule ignores comments 1`] = `""`;

packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/index.test.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,23 @@ describe('convert-esmodule', () => {
105105
expect(convertEsModule(code)).toMatchSnapshot();
106106
});
107107

108-
it.only('has good perf', () => {
108+
it('handles export mutations', () => {
109+
const code = `
110+
export default function test() {}
111+
112+
test = 5;
113+
`;
114+
expect(convertEsModule(code)).toMatchSnapshot();
115+
});
116+
117+
it('handles export mutations with no named function', () => {
118+
const code = `
119+
export default function() {}
120+
`;
121+
expect(convertEsModule(code)).toMatchSnapshot();
122+
});
123+
124+
it('has good perf', () => {
109125
/* eslint-disable */
110126
const code = require('./big-file');
111127

packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/index.ts

Lines changed: 83 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import * as meriyah from 'meriyah';
44
import * as astring from 'astring';
55
import { basename } from 'path';
6+
import { walk } from 'estree-walker';
7+
import { AssignmentExpression, ExpressionStatement } from 'meriyah/dist/estree';
68
import { Syntax as n } from './syntax';
79
import {
810
generateRequireStatement,
@@ -30,7 +32,7 @@ export function convertEsModule(code: string) {
3032
return usedName;
3133
};
3234

33-
const program = meriyah.parseModule(code, { next: true });
35+
let program = meriyah.parseModule(code, { next: true });
3436

3537
let i = 0;
3638

@@ -146,33 +148,96 @@ export function convertEsModule(code: string) {
146148
if (statement.declaration.type === n.FunctionDeclaration) {
147149
// @ts-ignore
148150
statement.declaration.type = n.FunctionExpression;
149-
}
150-
if (statement.declaration.type === n.ClassDeclaration) {
151+
} else if (statement.declaration.type === n.ClassDeclaration) {
151152
// @ts-ignore
152153
statement.declaration.type = n.ClassExpression;
153154
}
154155
const newDeclaration = statement.declaration as meriyah.ESTree.Expression;
155156

156157
// Create a var with the export
157-
program.body[i] = {
158-
type: n.VariableDeclaration,
159-
kind: 'var' as 'var',
158+
if (
159+
statement.declaration.type === n.ClassExpression ||
160+
statement.declaration.type === n.FunctionExpression
161+
) {
162+
if (!statement.declaration.id) {
163+
// If the function or class has no name, we give it to it
164+
statement.declaration.id = {
165+
type: n.Identifier,
166+
name: varName,
167+
};
168+
}
169+
program.body.splice(
170+
i,
171+
0,
172+
generateExportStatement(statement.declaration.id.name, 'default')
173+
);
174+
i++;
160175

161-
declarations: [
162-
{
163-
type: n.VariableDeclarator,
164-
id: {
165-
type: n.Identifier,
166-
name: varName,
176+
program.body[i] = statement.declaration;
177+
i++;
178+
} else {
179+
program.body[i] = {
180+
type: n.VariableDeclaration,
181+
kind: 'var' as 'var',
182+
183+
declarations: [
184+
{
185+
type: n.VariableDeclarator,
186+
id: {
187+
type: n.Identifier,
188+
name: varName,
189+
},
190+
init: newDeclaration,
167191
},
168-
init: newDeclaration,
169-
},
170-
],
171-
};
192+
],
193+
};
194+
i++;
172195

173-
i++;
196+
program.body.splice(
197+
i,
198+
0,
199+
generateExportStatement(varName, 'default')
200+
);
201+
}
174202

175-
program.body.splice(i, 0, generateExportStatement(varName, 'default'));
203+
if (
204+
newDeclaration.type === n.ClassDeclaration ||
205+
newDeclaration.type === n.FunctionExpression
206+
) {
207+
program = walk(program, {
208+
enter(node, parent, prop, index) {
209+
if (node.type === n.AssignmentExpression) {
210+
const { left } = node as AssignmentExpression;
211+
if (
212+
left.type === n.Identifier &&
213+
left.name === newDeclaration.id.name
214+
) {
215+
this.replace({
216+
type: n.ExpressionStatement,
217+
expression: {
218+
type: n.AssignmentExpression,
219+
left: {
220+
type: n.MemberExpression,
221+
object: {
222+
type: n.Identifier,
223+
name: 'exports',
224+
},
225+
computed: false,
226+
property: {
227+
type: n.Identifier,
228+
name: 'default',
229+
},
230+
},
231+
operator: '=' as '=',
232+
right: node,
233+
},
234+
} as ExpressionStatement);
235+
this.skip();
236+
}
237+
}
238+
},
239+
});
240+
}
176241
}
177242
} else if (statement.type === n.ImportDeclaration) {
178243
// @ts-ignore Wrong typing in lib?
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import _debug from '@codesandbox/common/lib/utils/debug';
2+
import Manager from '../eval/manager';
3+
4+
const debug = _debug('cs:compiler:benchmarks');
5+
6+
export function generateBenchmarkInterface(manager: Manager) {
7+
return {
8+
transpilation: async (n = 10, path = '/src/index.js') => {
9+
const module = manager.resolveModule(path, '/');
10+
11+
const times = [];
12+
for (let i = 0; i < n; i++) {
13+
const t = Date.now();
14+
// eslint-disable-next-line
15+
await manager.transpileModules(module);
16+
times.push(Date.now() - t);
17+
manager.clearTranspilationCache();
18+
}
19+
20+
debug(
21+
`Transpilation Benchmark: ${times.reduce((p, j) => p + j, 0) / n}ms`
22+
);
23+
},
24+
};
25+
}

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11431,6 +11431,11 @@ estree-walker@^0.6.0, estree-walker@^0.6.1:
1143111431
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
1143211432
integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==
1143311433

11434+
estree-walker@^1.0.1:
11435+
version "1.0.1"
11436+
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
11437+
integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
11438+
1143411439
[email protected], esutils@^2.0.0, esutils@^2.0.2:
1143511440
version "2.0.3"
1143611441
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"

0 commit comments

Comments
 (0)