Skip to content

Commit

Permalink
fix: tsconfig paths and HMR (#2028)
Browse files Browse the repository at this point in the history
* fix: ts config paths hmr

* fix: skip arg

* test: update snap

* docs: add hmr fallback plan

* test: fix

* chore: update
  • Loading branch information
segunadebayo authored Jan 18, 2024
1 parent c0af6db commit 1ed4df7
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 33 deletions.
7 changes: 7 additions & 0 deletions .changeset/heavy-sheep-accept.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@pandacss/types': patch
'@pandacss/core': patch
'@pandacss/node': patch
---

Fix issue where HMR doesn't work when tsconfig paths is used.
2 changes: 1 addition & 1 deletion packages/core/__tests__/import-map.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('import map', () => {
// ts paths
expect(
ctx.imports.match({ mod: 'anydir/css', alias: 'css', name: 'css' }, function resolveTsPath(mod) {
return { 'anydir/css': 'styled-system/css' }[mod]
if (mod === 'anydir/css') return `${ctx.config.cwd}/styled-system/css`
}),
).toBeTruthy()
})
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/file-matcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export class FileMatcher {

private createMatch = (mod: string, keys: string[]) => {
const mods = this.imports.filter((o) => {
const isFromMod = o.mod.includes(mod) || o.importMapValue === mod
const isFromMod = o.mod.includes(mod) || o.importMapValue?.includes(mod)
const isOneOfKeys = keys.includes(o.name)
return isFromMod && isOneOfKeys
})
Expand Down
11 changes: 6 additions & 5 deletions packages/core/src/import-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ export class ImportMap {
}

private getOutdir = () => {
const compilerOptions = this.context.conf.tsconfig?.compilerOptions ?? {}
const cwd = this.context.config.cwd
const { cwd, outdir } = this.context.config

const compilerOptions = this.context.conf.tsconfig?.compilerOptions ?? {}
const baseUrl = compilerOptions.baseUrl ?? ''
const relativeBaseUrl = baseUrl !== cwd ? baseUrl.replace(cwd, '').slice(1) : cwd

return this.context.config.outdir.replace(relativeBaseUrl, '')
const relativeBaseUrl = baseUrl !== cwd ? baseUrl.replace(cwd, '').slice(1) : cwd
return outdir.replace(relativeBaseUrl, '')
}

normalize = (map: string | ImportMapInput | undefined): ImportMapOutput => {
Expand Down Expand Up @@ -86,8 +86,9 @@ export class ImportMap {

// that might be a TS path mapping, it could be completely different from the actual path
const resolvedMod = resolveTsPath?.(result.mod)
const absMod = [this.context.config.cwd, mod].join('/')

if (resolvedMod?.includes(mod)) {
if (resolvedMod?.includes(absMod)) {
result.importMapValue = resolvedMod
return true
}
Expand Down
29 changes: 7 additions & 22 deletions packages/node/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { convertTsPathsToRegexes, loadConfig } from '@pandacss/config'
import { loadConfig } from '@pandacss/config'
import type { Config, ConfigResultWithHooks, PandaHooks } from '@pandacss/types'
import { createDebugger, createHooks } from 'hookable'
import { parse } from 'tsconfck'
import browserslist from 'browserslist'
import { createDebugger, createHooks } from 'hookable'
import { PandaContext } from './create-context'
import { loadTsConfig } from './load-tsconfig'

export async function loadConfigAndCreateContext(options: { cwd?: string; config?: Config; configPath?: string } = {}) {
const { config, configPath } = options
Expand All @@ -23,25 +23,10 @@ export async function loadConfigAndCreateContext(options: { cwd?: string; config
conf.config.browserslist ||= browserslist.findConfig(cwd)?.defaults
}

const tsconfigResult = await parse(conf.path, {
root: cwd,
// @ts-ignore
resolveWithEmptyIfConfigNotFound: true,
})

if (tsconfigResult) {
conf.tsconfig = tsconfigResult.tsconfig
conf.tsconfigFile = tsconfigResult.tsconfigFile

const options = tsconfigResult.tsconfig?.compilerOptions

if (options?.paths) {
const baseUrl = options.baseUrl
conf.tsOptions = {
baseUrl,
pathMappings: convertTsPathsToRegexes(options.paths, baseUrl ?? cwd),
}
}
const tsConfResult = await loadTsConfig(conf, cwd)

if (tsConfResult) {
Object.assign(conf, tsConfResult)
}

// Register user hooks
Expand Down
5 changes: 5 additions & 0 deletions packages/node/src/diff-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export class DiffEngine {
*/
async reloadConfigAndRefreshContext(fn?: (conf: LoadConfigResult) => void) {
const conf = await loadConfig({ cwd: this.ctx.config.cwd, file: this.ctx.conf.path })

// attach tsconfig options from previous config
const { tsconfig, tsconfigFile, tsOptions } = this.ctx.conf
Object.assign(conf, { tsconfig, tsconfigFile, tsOptions })

return this.refresh(conf, fn)
}

Expand Down
31 changes: 31 additions & 0 deletions packages/node/src/load-tsconfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { convertTsPathsToRegexes } from '@pandacss/config'
import type { LoadConfigResult, LoadTsConfigResult } from '@pandacss/types'
import { parse } from 'tsconfck'

export async function loadTsConfig(conf: LoadConfigResult, cwd: string): Promise<LoadTsConfigResult | undefined> {
const tsconfigResult = await parse(conf.path, {
root: cwd,
//@ts-ignore
resolveWithEmptyIfConfigNotFound: true,
})

if (!tsconfigResult) return

const { tsconfig, tsconfigFile } = tsconfigResult
const { compilerOptions } = tsconfig

const result: LoadTsConfigResult = {
tsconfig,
tsconfigFile,
}

if (compilerOptions?.paths) {
const baseUrl = compilerOptions.baseUrl
result.tsOptions = {
baseUrl,
pathMappings: convertTsPathsToRegexes(compilerOptions.paths, baseUrl ?? cwd),
}
}

return result
}
11 changes: 7 additions & 4 deletions packages/types/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,15 +364,18 @@ export interface ConfigTsOptions {
pathMappings: PathMapping[]
}

export interface LoadConfigResult {
export interface LoadTsConfigResult {
tsconfig?: TSConfig
tsOptions?: ConfigTsOptions
tsconfigFile?: string
}

export interface LoadConfigResult extends LoadTsConfigResult {
/** Config path */
path: string
config: UserConfig
serialized: string
deserialize: () => Config
tsconfig?: TSConfig
tsOptions?: ConfigTsOptions
tsconfigFile?: string
dependencies: string[]
}

Expand Down
31 changes: 31 additions & 0 deletions website/pages/docs/overview/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,37 @@ This error seems to be caused by process timing issues between file writes. This

---

### HMR does not work when I use `tsconfig` paths?

Panda tries to automatically infer and read the custom paths defined in `tsconfig.json` file. However, there might be scenarios where the hot module replacement doesn't work.

To fix this add the `importMap` option to your `panda.config.js` file, setting it's value to the specified `paths` in your `tsconfig.json` file.

```json
// tsconfig.json

{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"@my-path/*": ["./styled-system/*"]
}
}
}
```

```js
// panda.config.js

module.exports = {
importMap: '@my-path'
}
```

This will ensure that the paths are resolved correctly, and HMR works as expected.

---

### Why are my styles not applied?

Check that the [`@layer` rules](/docs/concepts/cascade-layers#layer-css) are set and the corresponding `.css` file is included. [If you're not using `postcss`](/docs/installation/cli), ensure that `styled-system/styles.css` is imported and that the `panda` command has been run (or is running with `--watch`).
Expand Down

3 comments on commit 1ed4df7

@vercel
Copy link

@vercel vercel bot commented on 1ed4df7 Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 1ed4df7 Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

panda-studio – ./

panda-app.vercel.app
panda-studio-git-main-chakra-ui.vercel.app
panda-studio-chakra-ui.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 1ed4df7 Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

panda-docs – ./website

panda-docs.vercel.app
panda-docs-git-main-chakra-ui.vercel.app
panda-docs-chakra-ui.vercel.app
panda-css.com

Please sign in to comment.