Skip to content

Commit 38c9a88

Browse files
authored
Upgrade: don't show error during upgrade when analyzing external URL import (#15040)
This PR improves the output of the upgrade tool when we are handling imports and the import happens to be an external URL. External URLs shouldn't and can't be upgraded, so printing an error message doesn't help the user. Additionally, if an `@import` is using the `url(…)` function, then we skip over it and continue with the rest of the imports. | Before | After | | --- | --- | | <img width="1455" alt="image" src="https://github.com/user-attachments/assets/1ee00ea4-68e1-4252-b1cf-30a04f608b75"> | <img width="1455" alt="image" src="https://github.com/user-attachments/assets/da1f3eaf-dedb-4b1b-bf73-93bdfee65759"> | Running this on github.com/parcel-bundler/parcel | Before | After | | -- | -- | | <img width="1552" alt="image" src="https://github.com/user-attachments/assets/89987444-8008-4edd-a907-6ad9276a86a0"> | <img width="1552" alt="image" src="https://github.com/user-attachments/assets/cc2a34ae-ef17-4ad1-b06d-097874400b4d"> |
1 parent ab9e2b7 commit 38c9a88

File tree

4 files changed

+43
-32
lines changed

4 files changed

+43
-32
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2121
- Ensure `flex` is suggested ([#15014](https://github.com/tailwindlabs/tailwindcss/pull/15014))
2222
- _Upgrade (experimental)_: Resolve imports when specifying a CSS entry point on the command-line ([#15010](https://github.com/tailwindlabs/tailwindcss/pull/15010))
2323
- _Upgrade (experimental)_: Resolve nearest Tailwind config file when CSS file does not contain `@config` ([#15001](https://github.com/tailwindlabs/tailwindcss/pull/15001))
24+
- _Upgrade (experimental)_: Improve output when CSS imports can not be found ([#15038](https://github.com/tailwindlabs/tailwindcss/pull/15038))
25+
- _Upgrade (experimental)_: Ignore analyzing imports with external URLs (e.g.: `@import "https://fonts.google.com"`) ([#15040](https://github.com/tailwindlabs/tailwindcss/pull/15040))
26+
- _Upgrade (experimental)_: Ignore analyzing imports with `url(…)` (e.g.: `@import url("https://fonts.google.com")`) ([#15040](https://github.com/tailwindlabs/tailwindcss/pull/15040))
2427

2528
### Changed
2629

packages/@tailwindcss-upgrade/src/codemods/migrate-import.test.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,22 @@
1-
import { __unstable__loadDesignSystem } from '@tailwindcss/node'
21
import dedent from 'dedent'
32
import postcss from 'postcss'
43
import { expect, it } from 'vitest'
5-
import type { UserConfig } from '../../../tailwindcss/src/compat/config/types'
64
import { migrateImport } from './migrate-import'
75

86
const css = dedent
97

10-
async function migrate(input: string, userConfig: UserConfig = {}) {
8+
async function migrate(input: string) {
119
return postcss()
12-
.use(
13-
migrateImport({
14-
designSystem: await __unstable__loadDesignSystem(`@import 'tailwindcss';`, {
15-
base: __dirname,
16-
}),
17-
userConfig,
18-
}),
19-
)
10+
.use(migrateImport())
2011
.process(input, { from: expect.getState().testPath })
2112
.then((result) => result.css)
2213
}
2314

2415
it('prints relative file imports as relative paths', async () => {
2516
expect(
2617
await migrate(css`
18+
@import url('https://example.com');
19+
2720
@import 'fixtures/test';
2821
@import 'fixtures/test.css';
2922
@import './fixtures/test.css';
@@ -62,7 +55,9 @@ it('prints relative file imports as relative paths', async () => {
6255
@import 'tailwindcss/theme';
6356
`),
6457
).toMatchInlineSnapshot(`
65-
"@import './fixtures/test.css';
58+
"@import url('https://example.com');
59+
60+
@import './fixtures/test.css';
6661
@import './fixtures/test.css';
6762
@import './fixtures/test.css';
6863
@import './fixtures/test.css';

packages/@tailwindcss-upgrade/src/codemods/migrate-import.ts

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,33 @@ export function migrateImport(): Plugin {
1212

1313
let promises: Promise<void>[] = []
1414
root.walkAtRules('import', (rule) => {
15-
let [firstParam, ...rest] = segment(rule.params, ' ')
16-
17-
let params = parseImportParams(ValueParser.parse(firstParam))
18-
19-
let isRelative = params.uri[0] === '.'
20-
let hasCssExtension = params.uri.endsWith('.css')
21-
22-
if (isRelative && hasCssExtension) {
23-
return
15+
try {
16+
let [firstParam, ...rest] = segment(rule.params, ' ')
17+
18+
let params = parseImportParams(ValueParser.parse(firstParam))
19+
20+
let isRelative = params.uri[0] === '.'
21+
let hasCssExtension = params.uri.endsWith('.css')
22+
23+
if (isRelative && hasCssExtension) {
24+
return
25+
}
26+
27+
let fullPath = resolve(dirname(file), params.uri)
28+
if (!hasCssExtension) fullPath += '.css'
29+
30+
promises.push(
31+
fs.stat(fullPath).then(() => {
32+
let ext = hasCssExtension ? '' : '.css'
33+
let path = isRelative ? params.uri : `./${params.uri}`
34+
rule.params = [`'${path}${ext}'`, ...rest].join(' ')
35+
}),
36+
)
37+
} catch {
38+
// When an error occurs while parsing the `@import` statement, we skip
39+
// the import. This will happen in cases where you import an external
40+
// URL.
2441
}
25-
26-
let fullPath = resolve(dirname(file), params.uri)
27-
if (!hasCssExtension) fullPath += '.css'
28-
29-
promises.push(
30-
fs.stat(fullPath).then(() => {
31-
let ext = hasCssExtension ? '' : '.css'
32-
let path = isRelative ? params.uri : `./${params.uri}`
33-
rule.params = [`'${path}${ext}'`, ...rest].join(' ')
34-
}),
35-
)
3642
})
3743

3844
await Promise.allSettled(promises)

packages/@tailwindcss-upgrade/src/migrate.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ export async function analyze(stylesheets: Stylesheet[]) {
120120
resolvedPath = resolveCssId(id, basePath)
121121
}
122122
} catch (err) {
123+
// Import is a URL, we don't want to process these, but also don't
124+
// want to show an error message for them.
125+
if (id.startsWith('http://') || id.startsWith('https://') || id.startsWith('//')) {
126+
return
127+
}
128+
129+
// Something went wrong, we can't resolve the import.
123130
error(
124131
`Failed to resolve import: ${highlight(id)} in ${highlight(relative(node.source?.input.file!, basePath))}. Skipping.`,
125132
{ prefix: '↳ ' },

0 commit comments

Comments
 (0)