Skip to content

Commit

Permalink
Add renderScript option (#969)
Browse files Browse the repository at this point in the history
  • Loading branch information
bluwy committed Feb 19, 2024
1 parent 6ffa54b commit a90d99e
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/gold-apples-shout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/compiler': minor
---

Adds a new `renderScript` option to render non-inline script tags using a `renderScript` function from `internalURL`, instead of stripping the script entirely
6 changes: 6 additions & 0 deletions cmd/astro-wasm/astro-wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ func makeTransformOptions(options js.Value) transform.TransformOptions {
scopedStyleStrategy = "where"
}

renderScript := false
if jsBool(options.Get("renderScript")) {
renderScript = true
}

return transform.TransformOptions{
Filename: filename,
NormalizedFilename: normalizedFilename,
Expand All @@ -139,6 +144,7 @@ func makeTransformOptions(options js.Value) transform.TransformOptions {
ScopedStyleStrategy: scopedStyleStrategy,
TransitionsAnimationURL: transitionsAnimationURL,
AnnotateSourceFile: annotateSourceFile,
RenderScript: renderScript,
}
}

Expand Down
4 changes: 4 additions & 0 deletions internal/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ type Node struct {
Expression bool
Transition bool
TransitionScope string
// Whether this node is a script that should be rendered with the `renderScript` runtime,
// so that the runtime handles how this is bundled and referenced.
HandledScript bool

Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node

Expand Down Expand Up @@ -233,6 +236,7 @@ func (n *Node) clone() *Node {
Attr: make([]Attribute, len(n.Attr)),
CustomElement: n.CustomElement,
Component: n.Component,
HandledScript: n.HandledScript,
Loc: n.Loc,
}
copy(m.Attr, n.Attr)
Expand Down
2 changes: 2 additions & 0 deletions internal/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ func (p *parser) addExpression() {
Expression: true,
Component: false,
CustomElement: false,
HandledScript: false,
Loc: p.generateLoc(),
})
}
Expand Down Expand Up @@ -433,6 +434,7 @@ func (p *parser) addElement() {
Fragment: isFragment(p.tok.Data),
Component: isComponent(p.tok.Data),
CustomElement: isCustomElement(p.tok.Data),
HandledScript: false,
Loc: p.generateLoc(),
})
}
Expand Down
21 changes: 21 additions & 0 deletions internal/printer/print-to-js.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type RenderOptions struct {
cssLen int
opts transform.TransformOptions
printedMaybeHead *bool
scriptCount *int
}

type ExtractedStatement struct {
Expand All @@ -71,13 +72,15 @@ type ExtractedStatement struct {

func printToJs(p *printer, n *Node, cssLen int, opts transform.TransformOptions) PrintResult {
printedMaybeHead := false
scriptCount := 0
render1(p, n, RenderOptions{
cssLen: cssLen,
isRoot: true,
isExpression: false,
depth: 0,
opts: opts,
printedMaybeHead: &printedMaybeHead,
scriptCount: &scriptCount,
})

return PrintResult{
Expand Down Expand Up @@ -136,6 +139,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {
opts: opts.opts,
cssLen: opts.cssLen,
printedMaybeHead: opts.printedMaybeHead,
scriptCount: opts.scriptCount,
})
}

Expand Down Expand Up @@ -253,6 +257,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {
opts: opts.opts,
cssLen: opts.cssLen,
printedMaybeHead: opts.printedMaybeHead,
scriptCount: opts.scriptCount,
})
if len(n.Loc) > 1 {
p.addSourceMapping(loc.Loc{Start: n.Loc[1].Start - 3})
Expand Down Expand Up @@ -346,6 +351,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {
opts: opts.opts,
cssLen: opts.cssLen,
printedMaybeHead: opts.printedMaybeHead,
scriptCount: opts.scriptCount,
})

// Print the closing of a tagged render function after
Expand All @@ -369,6 +375,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {
isClientOnly := isComponent && transform.HasAttr(n, "client:only")
isSlot := n.DataAtom == atom.Slot
isImplicit := false
isHandledScript := n.HandledScript
for _, a := range n.Attr {
if isSlot && a.Key == "is:inline" {
isSlot = false
Expand All @@ -386,6 +393,14 @@ func render1(p *printer, n *Node, opts RenderOptions) {
p.print(fmt.Sprintf("${%s(%s,'%s',", RENDER_COMPONENT, RESULT, n.Data))
case isSlot:
p.print(fmt.Sprintf("${%s(%s,%s[", RENDER_SLOT, RESULT, SLOTS))
case isHandledScript:
// import '/src/pages/index.astro?astro&type=script&index=0&lang.ts';
scriptUrl := fmt.Sprintf("%s?astro&type=script&index=%v&lang.ts", p.opts.Filename, *opts.scriptCount)
resolvedScriptUrl := transform.ResolveIdForMatch(scriptUrl, &p.opts)
escapedScriptUrl := escapeDoubleQuote(resolvedScriptUrl)
p.print(fmt.Sprintf("${%s(%s,\"%s\")}", RENDER_SCRIPT, RESULT, escapedScriptUrl))
*opts.scriptCount++
return
case isImplicit:
// do nothing
default:
Expand Down Expand Up @@ -528,6 +543,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {
opts: opts.opts,
cssLen: opts.cssLen,
printedMaybeHead: opts.printedMaybeHead,
scriptCount: opts.scriptCount,
})
}
}
Expand Down Expand Up @@ -562,6 +578,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {
opts: opts.opts,
cssLen: opts.cssLen,
printedMaybeHead: opts.printedMaybeHead,
scriptCount: opts.scriptCount,
})
}
p.printTemplateLiteralClose()
Expand Down Expand Up @@ -696,6 +713,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {
opts: opts.opts,
cssLen: opts.cssLen,
printedMaybeHead: opts.printedMaybeHead,
scriptCount: opts.scriptCount,
})
}
p.printTemplateLiteralClose()
Expand All @@ -717,6 +735,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {
opts: opts.opts,
cssLen: opts.cssLen,
printedMaybeHead: opts.printedMaybeHead,
scriptCount: opts.scriptCount,
})
if child.Type == ElementNode {
p.printTemplateLiteralClose()
Expand All @@ -736,6 +755,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {
opts: opts.opts,
cssLen: opts.cssLen,
printedMaybeHead: opts.printedMaybeHead,
scriptCount: opts.scriptCount,
})
}
p.printTemplateLiteralClose()
Expand All @@ -748,6 +768,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {
opts: opts.opts,
cssLen: opts.cssLen,
printedMaybeHead: opts.printedMaybeHead,
scriptCount: opts.scriptCount,
})
}
}
Expand Down
3 changes: 3 additions & 0 deletions internal/printer/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ var SPREAD_ATTRIBUTES = "$$spreadAttributes"
var DEFINE_STYLE_VARS = "$$defineStyleVars"
var DEFINE_SCRIPT_VARS = "$$defineScriptVars"
var CREATE_METADATA = "$$createMetadata"
var RENDER_SCRIPT = "$$renderScript"
var METADATA = "$$metadata"
var RESULT = "$$result"
var SLOTS = "$$slots"
Expand Down Expand Up @@ -137,6 +138,8 @@ func (p *printer) printInternalImports(importSpecifier string, opts *RenderOptio
p.print("renderTransition as " + RENDER_TRANSITION + ",\n ")
p.addNilSourceMapping()
p.print("createTransitionScope as " + CREATE_TRANSITION_SCOPE + ",\n ")
p.addNilSourceMapping()
p.print("renderScript as " + RENDER_SCRIPT + ",\n ")

// Only needed if using fallback `resolvePath` as it calls `$$metadata.resolvePath`
if opts.opts.ResolvePath == nil {
Expand Down
81 changes: 74 additions & 7 deletions internal/printer/printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var INTERNAL_IMPORTS = fmt.Sprintf("import {\n %s\n} from \"%s\";\n", strings.J
"defineScriptVars as " + DEFINE_SCRIPT_VARS,
"renderTransition as " + RENDER_TRANSITION,
"createTransitionScope as " + CREATE_TRANSITION_SCOPE,
"renderScript as " + RENDER_SCRIPT,
"createMetadata as " + CREATE_METADATA,
}, ",\n "), "http://localhost:3000/")
var PRELUDE = fmt.Sprintf(`const $$Component = %s(async ($$result, $$props, %s) => {
Expand Down Expand Up @@ -77,12 +78,13 @@ type metadata struct {
}

type testcase struct {
name string
source string
only bool
transitions bool
filename string
want want
name string
source string
only bool
transitions bool
transformOptions transform.TransformOptions
filename string
want want
}

type jsonTestcase struct {
Expand Down Expand Up @@ -1483,6 +1485,69 @@ import Widget2 from '../components/Widget2.astro';`},
code: `${$$maybeRenderHead($$result)}<div></div>`,
},
},
{
name: "script (renderScript: true)",
source: `<main><script>console.log("Hello");</script>`,
transformOptions: transform.TransformOptions{
RenderScript: true,
},
filename: "/src/pages/index.astro",
want: want{
metadata: metadata{hoisted: []string{fmt.Sprintf(`{ type: 'inline', value: %sconsole.log("Hello");%s }`, BACKTICK, BACKTICK)}},
code: `${$$maybeRenderHead($$result)}<main>${$$renderScript($$result,"/src/pages/index.astro?astro&type=script&index=0&lang.ts")}</main>`,
},
},
{
name: "script multiple (renderScript: true)",
source: `<main><script>console.log("Hello");</script><script>console.log("World");</script>`,
transformOptions: transform.TransformOptions{
RenderScript: true,
},
filename: "/src/pages/index.astro",
want: want{
metadata: metadata{
hoisted: []string{
fmt.Sprintf(`{ type: 'inline', value: %sconsole.log("World");%s }`, BACKTICK, BACKTICK),
fmt.Sprintf(`{ type: 'inline', value: %sconsole.log("Hello");%s }`, BACKTICK, BACKTICK),
},
},
code: `${$$maybeRenderHead($$result)}<main>${$$renderScript($$result,"/src/pages/index.astro?astro&type=script&index=0&lang.ts")}${$$renderScript($$result,"/src/pages/index.astro?astro&type=script&index=1&lang.ts")}</main>`,
},
},
{
name: "script external (renderScript: true)",
source: `<main><script src="./hello.js"></script>`,
transformOptions: transform.TransformOptions{
RenderScript: true,
},
filename: "/src/pages/index.astro",
want: want{
metadata: metadata{hoisted: []string{`{ type: 'external', src: './hello.js' }`}},
code: `${$$maybeRenderHead($$result)}<main>${$$renderScript($$result,"/src/pages/index.astro?astro&type=script&index=0&lang.ts")}</main>`,
},
},
{
name: "script inline (renderScript: true)",
source: `<main><script is:inline type="module">console.log("Hello");</script>`,
transformOptions: transform.TransformOptions{
RenderScript: true,
},
want: want{
code: `${$$maybeRenderHead($$result)}<main><script type="module">console.log("Hello");</script></main>`,
},
},
{
name: "script mixed handled and inline (renderScript: true)",
source: `<main><script>console.log("Hello");</script><script is:inline>console.log("World");</script>`,
transformOptions: transform.TransformOptions{
RenderScript: true,
},
filename: "/src/pages/index.astro",
want: want{
metadata: metadata{hoisted: []string{fmt.Sprintf(`{ type: 'inline', value: %sconsole.log("Hello");%s }`, BACKTICK, BACKTICK)}},
code: `${$$maybeRenderHead($$result)}<main>${$$renderScript($$result,"/src/pages/index.astro?astro&type=script&index=0&lang.ts")}<script>console.log("World");</script></main>`,
},
},
{
name: "text after title expression",
source: `<title>a {expr} b</title>`,
Expand Down Expand Up @@ -3456,8 +3521,10 @@ const items = ["Dog", "Cat", "Platipus"];

hash := astro.HashString(code)
transform.ExtractStyles(doc)
// combine from tt.transformOptions
transformOptions := transform.TransformOptions{
Scope: hash,
Scope: hash,
RenderScript: tt.transformOptions.RenderScript,
}
transform.Transform(doc, transformOptions, h) // note: we want to test Transform in context here, but more advanced cases could be tested separately
result := PrintToJS(code, doc, 0, transform.TransformOptions{
Expand Down
8 changes: 6 additions & 2 deletions internal/transform/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type TransformOptions struct {
ResolvePath func(string) string
PreprocessStyle interface{}
AnnotateSourceFile bool
RenderScript bool
}

func Transform(doc *astro.Node, opts TransformOptions, h *handler.Handler) *astro.Node {
Expand Down Expand Up @@ -81,8 +82,10 @@ func Transform(doc *astro.Node, opts TransformOptions, h *handler.Handler) *astr
NormalizeSetDirectives(doc, h)

// Important! Remove scripts from original location *after* walking the doc
for _, script := range doc.Scripts {
script.Parent.RemoveChild(script)
if !opts.RenderScript {
for _, script := range doc.Scripts {
script.Parent.RemoveChild(script)
}
}

// If we've emptied out all the nodes, this was a Fragment that only contained hoisted elements
Expand Down Expand Up @@ -389,6 +392,7 @@ func ExtractScript(doc *astro.Node, n *astro.Node, opts *TransformOptions, h *ha
// prepend node to maintain authored order
if shouldAdd {
doc.Scripts = append([]*astro.Node{n}, doc.Scripts...)
n.HandledScript = true
}
} else {
for _, attr := range n.Attr {
Expand Down
6 changes: 6 additions & 0 deletions packages/compiler/src/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ export interface TransformOptions {
resolvePath?: (specifier: string) => Promise<string>;
preprocessStyle?: (content: string, attrs: Record<string, string>) => null | Promise<PreprocessorResult | PreprocessorError>;
annotateSourceFile?: boolean;
/**
* Render script tags to be processed (e.g. script tags that have no attributes or only a `src` attribute)
* using a `renderScript` function from `internalURL`, instead of stripping the script entirely.
* @experimental
*/
renderScript?: boolean;
}

export type ConvertToTSXOptions = Pick<TransformOptions, 'filename' | 'normalizedFilename'>;
Expand Down

0 comments on commit a90d99e

Please sign in to comment.