Skip to content

Commit

Permalink
Handle bad CSS better (#515)
Browse files Browse the repository at this point in the history
* Handle bad CSS better

* Adding a changeset

* Make TransformResult return multiple style errors
  • Loading branch information
matthewp authored Sep 8, 2022
1 parent abda605 commit 6ebcb4f
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/great-schools-yawn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/compiler': minor
---

Allow preprocessStyle to return an error
30 changes: 22 additions & 8 deletions cmd/astro-wasm/astro-wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,11 @@ type TransformResult struct {
Scripts []HoistedScript `js:"scripts"`
HydratedComponents []HydratedComponent `js:"hydratedComponents"`
ClientOnlyComponents []HydratedComponent `js:"clientOnlyComponents"`
StyleError []string `js:"styleError"`
}

// This is spawned as a goroutine to preprocess style nodes using an async function passed from JS
func preprocessStyle(i int, style *astro.Node, transformOptions transform.TransformOptions, cb func()) {
func preprocessStyle(i int, style *astro.Node, transformOptions transform.TransformOptions, styleError *[]string, cb func()) {
defer cb()
if style.FirstChild == nil {
return
Expand All @@ -176,6 +177,14 @@ func preprocessStyle(i int, style *astro.Node, transformOptions transform.Transf
if data[0].Equal(js.Undefined()) || data[0].Equal(js.Null()) {
return
}
// If an error return, override the style's CSS so the compiler doesn't hang
// And return a styleError. The caller will use this to know that style processing failed.
if err := jsString(data[0].Get("error")); err != "" {
style.FirstChild.Data = ""
//*styleError = err
*styleError = append(*styleError, err)
return
}
str := jsString(data[0].Get("code"))
if str == "" {
return
Expand Down Expand Up @@ -228,6 +237,7 @@ func Transform() interface{} {
transformOptions := makeTransformOptions(js.Value(args[1]))
transformOptions.Scope = astro.HashFromSourceAndModuleId(source, transformOptions.ModuleId)

styleError := []string{}
handler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
resolve := args[0]

Expand Down Expand Up @@ -255,7 +265,7 @@ func Transform() interface{} {
for i, style := range doc.Styles {
wg.Add(1)
i := i
go preprocessStyle(i, style, transformOptions, wg.Done)
go preprocessStyle(i, style, transformOptions, &styleError, wg.Done)
}
}
}
Expand Down Expand Up @@ -357,11 +367,11 @@ func Transform() interface{} {
var value interface{}
switch transformOptions.SourceMap {
case "external":
value = createExternalSourceMap(source, result, css, &scripts, &hydratedComponents, &clientOnlyComponents, transformOptions)
value = createExternalSourceMap(source, result, css, &scripts, &hydratedComponents, &clientOnlyComponents, &styleError, transformOptions)
case "both":
value = createBothSourceMap(source, result, css, &scripts, &hydratedComponents, &clientOnlyComponents, transformOptions)
value = createBothSourceMap(source, result, css, &scripts, &hydratedComponents, &clientOnlyComponents, &styleError, transformOptions)
case "inline":
value = createInlineSourceMap(source, result, css, &scripts, &hydratedComponents, &clientOnlyComponents, transformOptions)
value = createInlineSourceMap(source, result, css, &scripts, &hydratedComponents, &clientOnlyComponents, &styleError, transformOptions)
default:
value = vert.ValueOf(TransformResult{
CSS: css,
Expand All @@ -371,6 +381,7 @@ func Transform() interface{} {
Scripts: scripts,
HydratedComponents: hydratedComponents,
ClientOnlyComponents: clientOnlyComponents,
StyleError: styleError,
})
}

Expand Down Expand Up @@ -404,7 +415,7 @@ func createSourceMapString(source string, result printer.PrintResult, transformO
}`, sourcemap.Sources[0], sourcemap.SourcesContent[0], sourcemap.Mappings)
}

func createExternalSourceMap(source string, result printer.PrintResult, css []string, scripts *[]HoistedScript, hydratedComponents *[]HydratedComponent, clientOnlyComponents *[]HydratedComponent, transformOptions transform.TransformOptions) interface{} {
func createExternalSourceMap(source string, result printer.PrintResult, css []string, scripts *[]HoistedScript, hydratedComponents *[]HydratedComponent, clientOnlyComponents *[]HydratedComponent, styleError *[]string, transformOptions transform.TransformOptions) interface{} {
return vert.ValueOf(TransformResult{
CSS: css,
Code: string(result.Output),
Expand All @@ -413,10 +424,11 @@ func createExternalSourceMap(source string, result printer.PrintResult, css []st
Scripts: *scripts,
HydratedComponents: *hydratedComponents,
ClientOnlyComponents: *clientOnlyComponents,
StyleError: *styleError,
})
}

func createInlineSourceMap(source string, result printer.PrintResult, css []string, scripts *[]HoistedScript, hydratedComponents *[]HydratedComponent, clientOnlyComponents *[]HydratedComponent, transformOptions transform.TransformOptions) interface{} {
func createInlineSourceMap(source string, result printer.PrintResult, css []string, scripts *[]HoistedScript, hydratedComponents *[]HydratedComponent, clientOnlyComponents *[]HydratedComponent, styleError *[]string, transformOptions transform.TransformOptions) interface{} {
sourcemapString := createSourceMapString(source, result, transformOptions)
inlineSourcemap := `//# sourceMappingURL=data:application/json;charset=utf-8;base64,` + base64.StdEncoding.EncodeToString([]byte(sourcemapString))
return vert.ValueOf(TransformResult{
Expand All @@ -427,10 +439,11 @@ func createInlineSourceMap(source string, result printer.PrintResult, css []stri
Scripts: *scripts,
HydratedComponents: *hydratedComponents,
ClientOnlyComponents: *clientOnlyComponents,
StyleError: *styleError,
})
}

func createBothSourceMap(source string, result printer.PrintResult, css []string, scripts *[]HoistedScript, hydratedComponents *[]HydratedComponent, clientOnlyComponents *[]HydratedComponent, transformOptions transform.TransformOptions) interface{} {
func createBothSourceMap(source string, result printer.PrintResult, css []string, scripts *[]HoistedScript, hydratedComponents *[]HydratedComponent, clientOnlyComponents *[]HydratedComponent, styleError *[]string, transformOptions transform.TransformOptions) interface{} {
sourcemapString := createSourceMapString(source, result, transformOptions)
inlineSourcemap := `//# sourceMappingURL=data:application/json;charset=utf-8;base64,` + base64.StdEncoding.EncodeToString([]byte(sourcemapString))
return vert.ValueOf(TransformResult{
Expand All @@ -441,5 +454,6 @@ func createBothSourceMap(source string, result printer.PrintResult, css []string
Scripts: *scripts,
HydratedComponents: *hydratedComponents,
ClientOnlyComponents: *clientOnlyComponents,
StyleError: *styleError,
})
}
7 changes: 6 additions & 1 deletion packages/compiler/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ export interface PreprocessorResult {
map?: string;
}

export interface PreprocessorError {
error: string;
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface ParseOptions {
position?: boolean;
Expand All @@ -24,7 +28,7 @@ export interface TransformOptions {
*/
as?: 'document' | 'fragment';
projectRoot?: string;
preprocessStyle?: (content: string, attrs: Record<string, string>) => Promise<PreprocessorResult>;
preprocessStyle?: (content: string, attrs: Record<string, string>) => null | Promise<PreprocessorResult | PreprocessorError>;
experimentalStaticExtraction?: boolean;
}

Expand Down Expand Up @@ -54,6 +58,7 @@ export interface TransformResult {
code: string;
map: string;
scope: string;
styleError: string[];
}

export interface TSXResult {
Expand Down
32 changes: 32 additions & 0 deletions packages/compiler/test/bad-styles/sass.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { test } from 'uvu';
import * as assert from 'uvu/assert';
import { transform } from '@astrojs/compiler';

const FIXTURE = `
<style lang="scss">
article:global(:is(h1, h2, h3, h4, h5, h6):hover {
color: purple;
}
</style>
<style lang="scss">
article:is(h1, h2, h3, h4, h5, h6)):hover {
color: purple;
}
</style>
`;

test('it works', async () => {
let result = await transform(FIXTURE, {
experimentalStaticExtraction: true,
pathname: '/@fs/users/astro/apps/pacman/src/pages/index.astro',
async preprocessStyle() {
return {
error: new Error('Unable to convert').message,
};
},
});
assert.equal(result.styleError.length, 2);
assert.equal(result.styleError[0], 'Unable to convert');
});

test.run();

0 comments on commit 6ebcb4f

Please sign in to comment.