Compare commits
1 commit
main
...
revert-hoi
Author | SHA1 | Date | |
---|---|---|---|
|
15b4276dc4 |
3 changed files with 11 additions and 133 deletions
5
.changeset/clean-bags-mate.md
Normal file
5
.changeset/clean-bags-mate.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Revert hoisted scripts analysis to prevent missing scripts during build
|
|
@ -1,11 +1,9 @@
|
||||||
import type { ModuleInfo, PluginContext } from 'rollup';
|
import type { PluginContext } from 'rollup';
|
||||||
import type { Plugin as VitePlugin } from 'vite';
|
import type { Plugin as VitePlugin } from 'vite';
|
||||||
import type { PluginMetadata as AstroPluginMetadata } from '../../../vite-plugin-astro/types';
|
import type { PluginMetadata as AstroPluginMetadata } from '../../../vite-plugin-astro/types';
|
||||||
import type { BuildInternals } from '../internal.js';
|
import type { BuildInternals } from '../internal.js';
|
||||||
import type { AstroBuildPlugin } from '../plugin.js';
|
import type { AstroBuildPlugin } from '../plugin.js';
|
||||||
|
|
||||||
import type { ExportDefaultDeclaration, ExportNamedDeclaration, ImportDeclaration } from 'estree';
|
|
||||||
import { walk } from 'estree-walker';
|
|
||||||
import { PROPAGATED_ASSET_FLAG } from '../../../content/consts.js';
|
import { PROPAGATED_ASSET_FLAG } from '../../../content/consts.js';
|
||||||
import { prependForwardSlash } from '../../../core/path.js';
|
import { prependForwardSlash } from '../../../core/path.js';
|
||||||
import { getTopLevelPages, moduleIsTopLevelPage, walkParentInfos } from '../graph.js';
|
import { getTopLevelPages, moduleIsTopLevelPage, walkParentInfos } from '../graph.js';
|
||||||
|
@ -19,102 +17,6 @@ function isPropagatedAsset(id: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns undefined if the parent does not import the child, string[] of the reexports if it does
|
|
||||||
*/
|
|
||||||
async function doesParentImportChild(
|
|
||||||
this: PluginContext,
|
|
||||||
parentInfo: ModuleInfo,
|
|
||||||
childInfo: ModuleInfo | undefined,
|
|
||||||
childExportNames: string[] | 'dynamic' | undefined
|
|
||||||
): Promise<'no' | 'dynamic' | string[]> {
|
|
||||||
if (!childInfo || !parentInfo.ast || !childExportNames) return 'no';
|
|
||||||
|
|
||||||
if (childExportNames === 'dynamic' || parentInfo.dynamicallyImportedIds?.includes(childInfo.id)) {
|
|
||||||
return 'dynamic';
|
|
||||||
}
|
|
||||||
|
|
||||||
const imports: Array<ImportDeclaration> = [];
|
|
||||||
const exports: Array<ExportNamedDeclaration | ExportDefaultDeclaration> = [];
|
|
||||||
walk(parentInfo.ast, {
|
|
||||||
enter(node) {
|
|
||||||
if (node.type === 'ImportDeclaration') {
|
|
||||||
imports.push(node as ImportDeclaration);
|
|
||||||
} else if (
|
|
||||||
node.type === 'ExportDefaultDeclaration' ||
|
|
||||||
node.type === 'ExportNamedDeclaration'
|
|
||||||
) {
|
|
||||||
exports.push(node as ExportNamedDeclaration | ExportDefaultDeclaration);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// All of the aliases the current component is imported as
|
|
||||||
const importNames: string[] = [];
|
|
||||||
// All of the aliases the child component is exported as
|
|
||||||
const exportNames: string[] = [];
|
|
||||||
|
|
||||||
for (const node of imports) {
|
|
||||||
const resolved = await this.resolve(node.source.value as string, parentInfo.id);
|
|
||||||
if (!resolved || resolved.id !== childInfo.id) continue;
|
|
||||||
for (const specifier of node.specifiers) {
|
|
||||||
// TODO: handle these?
|
|
||||||
if (specifier.type === 'ImportNamespaceSpecifier') continue;
|
|
||||||
const name =
|
|
||||||
specifier.type === 'ImportDefaultSpecifier' ? 'default' : specifier.imported.name;
|
|
||||||
// If we're importing the thing that the child exported, store the local name of what we imported
|
|
||||||
if (childExportNames.includes(name)) {
|
|
||||||
importNames.push(specifier.local.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const node of exports) {
|
|
||||||
if (node.type === 'ExportDefaultDeclaration') {
|
|
||||||
if (node.declaration.type === 'Identifier' && importNames.includes(node.declaration.name)) {
|
|
||||||
exportNames.push('default');
|
|
||||||
// return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// handle `export { x } from 'something';`, where the export and import are in the same node
|
|
||||||
if (node.source) {
|
|
||||||
const resolved = await this.resolve(node.source.value as string, parentInfo.id);
|
|
||||||
if (!resolved || resolved.id !== childInfo.id) continue;
|
|
||||||
for (const specifier of node.specifiers) {
|
|
||||||
if (childExportNames.includes(specifier.local.name)) {
|
|
||||||
importNames.push(specifier.local.name);
|
|
||||||
exportNames.push(specifier.exported.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (node.declaration) {
|
|
||||||
if (node.declaration.type !== 'VariableDeclaration') continue;
|
|
||||||
for (const declarator of node.declaration.declarations) {
|
|
||||||
if (declarator.init?.type !== 'Identifier') continue;
|
|
||||||
if (declarator.id.type !== 'Identifier') continue;
|
|
||||||
if (importNames.includes(declarator.init.name)) {
|
|
||||||
exportNames.push(declarator.id.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const specifier of node.specifiers) {
|
|
||||||
if (importNames.includes(specifier.local.name)) {
|
|
||||||
exportNames.push(specifier.exported.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!importNames.length) return 'no';
|
|
||||||
|
|
||||||
// If the component is imported by another component, assume it's in use
|
|
||||||
// and start tracking this new component now
|
|
||||||
if (parentInfo.id.endsWith('.astro')) {
|
|
||||||
exportNames.push('default');
|
|
||||||
} else if (parentInfo.id.endsWith('.mdx')) {
|
|
||||||
exportNames.push('Content');
|
|
||||||
}
|
|
||||||
|
|
||||||
return exportNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
||||||
function hoistedScriptScanner() {
|
function hoistedScriptScanner() {
|
||||||
const uniqueHoistedIds = new Map<string, string>();
|
const uniqueHoistedIds = new Map<string, string>();
|
||||||
|
@ -127,11 +29,7 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
||||||
>();
|
>();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async scan(
|
scan(this: PluginContext, scripts: AstroPluginMetadata['astro']['scripts'], from: string) {
|
||||||
this: PluginContext,
|
|
||||||
scripts: AstroPluginMetadata['astro']['scripts'],
|
|
||||||
from: string
|
|
||||||
) {
|
|
||||||
const hoistedScripts = new Set<string>();
|
const hoistedScripts = new Set<string>();
|
||||||
for (let i = 0; i < scripts.length; i++) {
|
for (let i = 0; i < scripts.length; i++) {
|
||||||
const hid = `${from.replace('/@fs', '')}?astro&type=script&index=${i}&lang.ts`;
|
const hid = `${from.replace('/@fs', '')}?astro&type=script&index=${i}&lang.ts`;
|
||||||
|
@ -139,35 +37,9 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hoistedScripts.size) {
|
if (hoistedScripts.size) {
|
||||||
const depthsToChildren = new Map<number, ModuleInfo>();
|
for (const [parentInfo] of walkParentInfos(from, this, function until(importer) {
|
||||||
const depthsToExportNames = new Map<number, string[] | 'dynamic'>();
|
|
||||||
// The component export from the original component file will always be default.
|
|
||||||
depthsToExportNames.set(0, ['default']);
|
|
||||||
|
|
||||||
for (const [parentInfo, depth] of walkParentInfos(from, this, function until(importer) {
|
|
||||||
return isPropagatedAsset(importer);
|
return isPropagatedAsset(importer);
|
||||||
})) {
|
})) {
|
||||||
depthsToChildren.set(depth, parentInfo);
|
|
||||||
// If at any point
|
|
||||||
if (depth > 0) {
|
|
||||||
// Check if the component is actually imported:
|
|
||||||
const childInfo = depthsToChildren.get(depth - 1);
|
|
||||||
const childExportNames = depthsToExportNames.get(depth - 1);
|
|
||||||
|
|
||||||
const doesImport = await doesParentImportChild.call(
|
|
||||||
this,
|
|
||||||
parentInfo,
|
|
||||||
childInfo,
|
|
||||||
childExportNames
|
|
||||||
);
|
|
||||||
|
|
||||||
if (doesImport === 'no') {
|
|
||||||
// Break the search if the parent doesn't import the child.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
depthsToExportNames.set(depth, doesImport);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPropagatedAsset(parentInfo.id)) {
|
if (isPropagatedAsset(parentInfo.id)) {
|
||||||
for (const [nestedParentInfo] of walkParentInfos(from, this)) {
|
for (const [nestedParentInfo] of walkParentInfos(from, this)) {
|
||||||
if (moduleIsTopLevelPage(nestedParentInfo)) {
|
if (moduleIsTopLevelPage(nestedParentInfo)) {
|
||||||
|
@ -274,7 +146,7 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan hoisted scripts
|
// Scan hoisted scripts
|
||||||
await hoistScanner.scan.call(this, astro.scripts, id);
|
hoistScanner.scan.call(this, astro.scripts, id);
|
||||||
|
|
||||||
if (astro.clientOnlyComponents.length) {
|
if (astro.clientOnlyComponents.length) {
|
||||||
const clientOnlys: string[] = [];
|
const clientOnlys: string[] = [];
|
||||||
|
|
|
@ -2,7 +2,8 @@ import { expect } from 'chai';
|
||||||
import { loadFixture } from './test-utils.js';
|
import { loadFixture } from './test-utils.js';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
|
|
||||||
describe('Hoisted Imports', () => {
|
// Skip for now until we can implement a better hoisted scripts solution
|
||||||
|
describe.skip('Hoisted Imports', () => {
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
|
Loading…
Reference in a new issue