Skip to content

Commit

Permalink
fix(utils): support for export enum … and transpiled reexports (#1336)
Browse files Browse the repository at this point in the history
  • Loading branch information
Anber committed Sep 15, 2023
1 parent aa10045 commit f8b9bff
Show file tree
Hide file tree
Showing 8 changed files with 465 additions and 280 deletions.
8 changes: 8 additions & 0 deletions .changeset/neat-worms-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@linaria/babel-preset': patch
'@linaria/shaker': patch
'@linaria/testkit': patch
'@linaria/utils': patch
---

Improved exports finder so it works with pure TS files and better detects transpiled reexports.
4 changes: 2 additions & 2 deletions packages/babel/src/transform/generators/getExports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ export function* getExports(
this.services.babel.traverse(loadedAndParsed.ast!, {
Program(path) {
const { exports, reexports } = collectExportsAndImports(path, 'disabled');
exports.forEach((e) => {
result.push(e.exported);
Object.keys(exports).forEach((token) => {
result.push(token);
});

reexports.forEach((e) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/babel/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { BabelFile, PluginPass } from '@babel/core';
import type { NodePath } from '@babel/traverse';
import type { File } from '@babel/types';
import type { File, Program } from '@babel/types';
import type { RawSourceMap } from 'source-map';

import type { Debugger } from '@linaria/logger';
Expand Down Expand Up @@ -84,5 +84,5 @@ export type MissedBabelCoreTypes = {
File: new (
options: { filename: string },
file: { ast: File; code: string }
) => { path: NodePath<File> };
) => { path: NodePath<Program> };
};
12 changes: 3 additions & 9 deletions packages/shaker/src/plugins/__tests__/shaker-plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ const keep =
configFile: false,
filename,
presets,
sourceType: /(?:^|\*\/|;)\s*(?:export|import)\s/m.test(formattedCode)
? 'module'
: 'script',
plugins: [
[
shakerPlugin,
Expand Down Expand Up @@ -296,15 +299,6 @@ describe('shaker', () => {
});

it('deletes non-default exports when importing default export of a module with an __esModule: true property', () => {
/* without workaround, this will be transformed by shaker to:
const n = require('n');
const defaultExports = {
createContext: n.createContext
};
exports.default = defaultExports;
i.e, exports.createContext is deleted
*/
const { code } = keep(['default'])`
const n = require('n');
const defaultExports = { createContext: n.createContext }
Expand Down
83 changes: 43 additions & 40 deletions packages/shaker/src/plugins/shaker-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type {
} from '@babel/types';

import { createCustomDebug } from '@linaria/logger';
import type { IExport, IMetadata, IReexport, IState } from '@linaria/utils';
import type { Exports, IMetadata, IState } from '@linaria/utils';
import {
applyAction,
collectExportsAndImports,
Expand Down Expand Up @@ -69,9 +69,12 @@ function rearrangeExports(
{ types: t }: Core,
root: NodePath<Program>,
exportRefs: Map<string, NodePath<MemberExpression>[]>,
exports: IExport[]
): IExport[] {
let rearranged = [...exports];
exports: Exports
): Exports {
const rearranged = {
...exports,
};

const rootScope = root.scope;
exportRefs.forEach((refs, name) => {
if (refs.length <= 1) {
Expand Down Expand Up @@ -110,14 +113,7 @@ function rearrangeExports(
const local = pushed.get('expression.right') as NodePath<Identifier>;
reference(local);

rearranged = rearranged.map((exp) =>
exp.exported === name
? {
...exp,
local,
}
: exp
);
rearranged[name] = local;
});

return rearranged;
Expand Down Expand Up @@ -160,10 +156,7 @@ export default function shakerPlugin(
collected.exports
);

const findExport = (name: string) =>
exports.find((i) => i.exported === name);

collected.exports.forEach(({ local }) => {
Object.values(collected.exports).forEach((local) => {
if (local.isAssignmentExpression()) {
const left = local.get('left');
if (left.isIdentifier()) {
Expand All @@ -174,8 +167,8 @@ export default function shakerPlugin(
}
});

const hasLinariaPreval = findExport('__linariaPreval') !== undefined;
const hasDefault = findExport('default') !== undefined;
const hasLinariaPreval = exports.__linariaPreval !== undefined;
const hasDefault = exports.default !== undefined;

// If __linariaPreval is not exported, we can remove it from onlyExports
if (onlyExportsSet.has('__linariaPreval') && !hasLinariaPreval) {
Expand All @@ -185,8 +178,9 @@ export default function shakerPlugin(
if (onlyExportsSet.size === 0) {
// Fast-lane: if there are no exports to keep, we can just shake out the whole file
this.imports = [];
this.exports = [];
this.exports = {};
this.reexports = [];
this.deadExports = Object.keys(exports);

file.path.get('body').forEach((p) => {
p.remove();
Expand All @@ -210,34 +204,33 @@ export default function shakerPlugin(
this.imports = collected.imports;
this.exports = exports;
this.reexports = collected.reexports;
this.deadExports = [];
return;
}

if (!onlyExportsSet.has('*')) {
const aliveExports = new Set<IExport | IReexport>();
const aliveExports = new Set<NodePath>();
const importNames = collected.imports.map(({ imported }) => imported);

exports.forEach((exp) => {
if (onlyExportsSet.has(exp.exported)) {
aliveExports.add(exp);
} else if (
importNames.includes((exp.local.node as NodeWithName).name || '')
) {
aliveExports.add(exp);
Object.entries(exports).forEach(([exported, local]) => {
if (onlyExportsSet.has(exported)) {
aliveExports.add(local);
} else if (
[...aliveExports].some((liveExp) => liveExp.local === exp.local)
importNames.includes((local.node as NodeWithName).name || '')
) {
aliveExports.add(local);
} else if ([...aliveExports].some((alive) => alive === local)) {
// It's possible to export multiple values from a single variable initializer, e.g
// export const { foo, bar } = baz();
// We need to treat all of them as used if any of them are used, since otherwise
// we'll attempt to delete the baz() call
aliveExports.add(exp);
aliveExports.add(local);
}
});

collected.reexports.forEach((exp) => {
if (onlyExportsSet.has(exp.exported)) {
aliveExports.add(exp);
aliveExports.add(exp.local);
}
});

Expand All @@ -251,15 +244,13 @@ export default function shakerPlugin(

if (ifUnknownExport === 'reexport-all') {
// If there are unknown exports, we have keep alive all re-exports.
exports.forEach((exp) => {
if (exp.exported === '*') {
aliveExports.add(exp);
}
});
if (exports['*'] !== undefined) {
aliveExports.add(exports['*']);
}

collected.reexports.forEach((exp) => {
if (exp.exported === '*') {
aliveExports.add(exp);
aliveExports.add(exp.local);
}
});
}
Expand All @@ -268,14 +259,16 @@ export default function shakerPlugin(
this.imports = collected.imports;
this.exports = exports;
this.reexports = collected.reexports;
this.deadExports = [];

return;
}
}

const forDeleting = [...exports, ...collected.reexports]
.filter((exp) => !aliveExports.has(exp))
.map((exp) => exp.local);
const forDeleting = [
...Object.values(exports),
...collected.reexports.map((i) => i.local),
].filter((exp) => !aliveExports.has(exp));

if (!keepSideEffects && !importedAsSideEffect) {
// Remove all imports that don't import something explicitly and should not be kept
Expand Down Expand Up @@ -331,7 +324,17 @@ export default function shakerPlugin(
}

this.imports = withoutRemoved(collected.imports);
this.exports = withoutRemoved(exports);
this.exports = {};
this.deadExports = [];

Object.entries(exports).forEach(([exported, local]) => {
if (isRemoved(local)) {
this.deadExports.push(exported);
} else {
this.exports[exported] = local;
}
});

this.reexports = withoutRemoved(collected.reexports);
},
visitor: {},
Expand Down

0 comments on commit f8b9bff

Please sign in to comment.