Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/keep-user-alias.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'vite-plugin-solid': patch
---

The plugin no longer changes `resolve.alias`. An alias object in your config now keeps priority over aliases that later plugins add, such as `vite-plugin-node-polyfills` mapping `path` (#130).
3 changes: 3 additions & 0 deletions .github/workflows/vitest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ jobs:
- name: Install project dependencies
run: pnpm i

- name: Run unit tests
run: pnpm run test:unit

- name: Install playwright browser
working-directory: examples/vite-6
run: pnpm exec playwright install chromium
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"prepublishOnly": "pnpm build",
"release": "pnpm build && changeset publish",
"check": "package-check",
"test": "node scripts/test-examples.ts"
"test": "node scripts/test-examples.ts",
"test:unit": "vitest run"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -68,7 +69,8 @@
"rollup-plugin-cleaner": "^1.0.0",
"solid-js": "^1.9.3",
"typescript": "^5.2.2",
"vite": "^6.0.0"
"vite": "^6.0.0",
"vitest": "^3.0.7"
},
"peerDependencies": {
"@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.0.0 || ^7.0.0",
Expand Down
37 changes: 36 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

78 changes: 78 additions & 0 deletions src/alias.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { mkdtemp, mkdir, realpath, rm, symlink, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { build, createServer, type Plugin, type Rollup } from 'vite';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import solidPlugin from './index.js';

let root: string;

beforeAll(async () => {
root = await realpath(await mkdtemp(path.join(tmpdir(), 'solid-alias-')));
await writeFile(path.join(root, 'package.json'), JSON.stringify({ name: 'app', type: 'module' }));
await writeFile(path.join(root, 'entry.js'), "export { join } from 'path/posix';\n");
await writeFile(path.join(root, 'user-posix.js'), 'export const join = "user alias";\n');
// The `path` polyfill has no `posix` subpath, like path-browserify.
await mkdir(path.join(root, 'polyfill'));
await writeFile(path.join(root, 'polyfill/index.js'), 'export const join = "polyfill";\n');
});

afterAll(async () => {
await rm(root, { recursive: true, force: true });
});

describe('resolve.alias', () => {
// #130: the plugin turned the user's alias object into an array. Vite then
// put aliases from later plugins first, so `path` matched `path/posix`.
it('keeps user object aliases ahead of aliases added by later plugins', async () => {
const polyfills: Plugin = {
name: 'test-polyfills',
config: () => ({ resolve: { alias: { path: path.join(root, 'polyfill') } } }),
};
const result = (await build({
root,
configFile: false,
logLevel: 'silent',
plugins: [solidPlugin(), polyfills],
resolve: { alias: { 'path/posix': path.join(root, 'user-posix.js') } },
build: {
write: false,
minify: false,
rollupOptions: { input: path.join(root, 'entry.js'), preserveEntrySignatures: 'strict' },
},
})) as Rollup.RollupOutput | Rollup.RollupOutput[];
const output = Array.isArray(result) ? result[0] : result;
const code = output.output
.filter((chunk): chunk is Rollup.OutputChunk => chunk.type === 'chunk')
.map((chunk) => chunk.code)
.join('\n');
expect(code).toContain('"user alias"');
});

it('still serves the HMR runtime for the solid-refresh import', async () => {
await symlink(
fileURLToPath(new URL('../node_modules', import.meta.url)),
path.join(root, 'node_modules'),
'dir',
);
await writeFile(path.join(root, 'App.tsx'), 'export const App = () => <div>app</div>;\n');
const server = await createServer({
root,
configFile: false,
appType: 'custom',
logLevel: 'silent',
server: { middlewareMode: true, ws: false, watch: null },
optimizeDeps: { noDiscovery: true, include: [] },
plugins: [solidPlugin()],
});
try {
const app = await server.transformRequest('/App.tsx');
expect(app?.code).toMatch(/from ["']\/@solid-refresh["']/);
const runtime = await server.transformRequest('/@solid-refresh');
expect(runtime?.code).toContain('$$registry');
} finally {
await server.close();
}
});
});
25 changes: 8 additions & 17 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { readFileSync } from 'fs';
import { mergeAndConcat } from 'merge-anything';
import { createRequire } from 'module';
import solidRefresh from 'solid-refresh/babel';
import type { Alias, AliasOptions, FilterPattern, Plugin } from 'vite';
import type { FilterPattern, Plugin } from 'vite';
import { createFilter, version } from 'vite';
import { crawlFrameworkPkgs } from 'vitefu';

Expand Down Expand Up @@ -225,8 +225,9 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin {
projectRoot = userConfig.root;
isTestMode = userConfig.mode === 'test';

if (!userConfig.resolve) userConfig.resolve = {};
userConfig.resolve.alias = normalizeAliases(userConfig.resolve && userConfig.resolve.alias);
// Leave the user's `resolve.alias` as it is. Turning an object into an
// array changes how Vite merges it with aliases from later plugins:
// their entries then take priority over the user's. #130

solidPkgsConfig = await crawlFrameworkPkgs({
viteUserConfig: userConfig,
Expand Down Expand Up @@ -287,7 +288,6 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin {
...(userConfig.mode === 'test' && !options.ssr ? ['browser'] : []),
],
dedupe: nestedDeps,
alias: [{ find: /^solid-refresh$/, replacement: runtimePublicPath }],
},
optimizeDeps: {
include: [...nestedDeps, ...solidPkgsConfig.optimizeDeps.include],
Expand Down Expand Up @@ -346,7 +346,10 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin {
},

resolveId(id) {
if (id === runtimePublicPath) return id;
// `solid-refresh` is the import added by the HMR transform. It is
// resolved here rather than through `resolve.alias`, because adding an
// alias array would also change how the user's aliases merge. #130
if (id === runtimePublicPath || id === 'solid-refresh') return runtimePublicPath;
},

load(id) {
Expand Down Expand Up @@ -456,15 +459,3 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin {
},
};
}

/**
* This basically normalize all aliases of the config into
* the array format of the alias.
*
* eg: alias: { '@': 'src/' } => [{ find: '@', replacement: 'src/' }]
*/
function normalizeAliases(alias: AliasOptions = []): Alias[] {
return Array.isArray(alias)
? alias
: Object.entries(alias).map(([find, replacement]) => ({ find, replacement }));
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"src", "cypress"
],
"exclude": [
"**/*.spec.ts"
"**/*.spec.ts", "**/*.test.ts"
],
"compilerOptions": {
"target": "ESNext",
Expand Down
10 changes: 10 additions & 0 deletions vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineConfig } from 'vitest/config';

// The plugin's own unit tests (`pnpm test:unit`). The example apps under
// examples/* carry their own vitest configs and run through `pnpm test`.
export default defineConfig({
test: {
include: ['src/**/*.test.ts'],
environment: 'node',
},
});
Loading