Skip to content

Conversation

@Gianthard-cyh
Copy link

@Gianthard-cyh Gianthard-cyh commented Jul 14, 2025

Problem statement

See #13623.

Change summary

Add imports for TransformContext in compiler-vapor.
Modify expression generator to treat the expression of imported public asset properly.
Generate asset imports.

Closes #13623.

@coderabbitai
Copy link

coderabbitai bot commented Jul 14, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

Size Report

Bundles

File Size Gzip Brotli
compiler-dom.global.prod.js 84.1 kB 29.8 kB 26.2 kB
runtime-dom.global.prod.js 104 kB 39.1 kB 35.2 kB
vue.global.prod.js 162 kB 59.3 kB 52.8 kB

Usages

Name Size Gzip Brotli
createApp (CAPI only) 47.2 kB 18.5 kB 16.9 kB
createApp 56 kB 21.6 kB 19.7 kB
createApp + vaporInteropPlugin 68.5 kB 25.8 kB 23.6 kB
createVaporApp 21 kB 8.31 kB 7.6 kB
createSSRApp 60.3 kB 23.4 kB 21.3 kB
defineCustomElement 61 kB 23.1 kB 21.1 kB
overall 70.5 kB 26.8 kB 24.5 kB

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jul 15, 2025

Open in StackBlitz

@vue/compiler-core

npm i https://pkg.pr.new/@vue/compiler-core@13630

@vue/compiler-dom

npm i https://pkg.pr.new/@vue/compiler-dom@13630

@vue/compiler-sfc

npm i https://pkg.pr.new/@vue/compiler-sfc@13630

@vue/compiler-ssr

npm i https://pkg.pr.new/@vue/compiler-ssr@13630

@vue/compiler-vapor

npm i https://pkg.pr.new/@vue/compiler-vapor@13630

@vue/reactivity

npm i https://pkg.pr.new/@vue/reactivity@13630

@vue/runtime-core

npm i https://pkg.pr.new/@vue/runtime-core@13630

@vue/runtime-dom

npm i https://pkg.pr.new/@vue/runtime-dom@13630

@vue/runtime-vapor

npm i https://pkg.pr.new/@vue/runtime-vapor@13630

@vue/server-renderer

npm i https://pkg.pr.new/@vue/server-renderer@13630

@vue/shared

npm i https://pkg.pr.new/@vue/shared@13630

vue

npm i https://pkg.pr.new/vue@13630

@vue/compat

npm i https://pkg.pr.new/@vue/compat@13630

commit: d50620c


exports[`compile > asset imports > from public directory 1`] = `
"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
import _imports_0 from '/vite.svg';
Copy link
Member

@edison1105 edison1105 Jul 15, 2025

Choose a reason for hiding this comment

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

import _imports_0 from '/vite.svg';
const t0 = _template(`<img src="${_imports_0}">`, true)

It should be done like this to avoid renderEffect and setProp.

Copy link
Author

@Gianthard-cyh Gianthard-cyh Jul 15, 2025

Choose a reason for hiding this comment

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

Hi! Thanks for the suggestion — I’ve tried to move _imports_0 into the template string as recommended to avoid renderEffect and setProp.

export function genTemplates(
templates: string[],
rootIndex: number | undefined,
{ helper }: CodegenContext,
): string {
return templates
.map(
(template, i) =>
`const t${i} = ${helper('template')}(${JSON.stringify(
template,
)}${i === rootIndex ? ', true' : ''})\n`,
)
.join('')
}

However, the genTemplates function still uses JSON.stringify(), which wraps the entire template in double quotes and escapes inner quotes. That prevents me from generating template literals like:

const t0 = _template(`<img src="${_imports_0}">`, true)

I also tried string concatenation:

template += ` ${key.content}=""+${values[0].content}+""`

But this results in a normal string with escaped quotes.

const t0 = _template("<img src=\"\"+_imports_0+\"\">")

Let me know if you have any thoughts or preferred direction on this — happy to collaborate on the final approach!

Copy link
Member

Choose a reason for hiding this comment

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

It should be easier to implement using string concatenation. For example, like this:

  • Wrap the variable with special characters
template += ` ${key.content}="$\{${values[0].content}\}$"`
  • In genTemplates, replace the variable with string concatenation
${JSON.stringify(template).replace(/\${_imports_(\d+)}\$/g,'"+ _imports_$1 +"')

@Gianthard-cyh
Copy link
Author

Hi! @edison1105
I've committed a version that replaces JSON.stringify with a custom escape function, and wraps the template strings with backticks (`) instead of double quotes ("). I bundled and tested the output and it successfully fixes the issue.

This change breaks the existing unit tests because previous snapshots were based on template strings wrapped with double quotes. I'm not sure whether this change might break anything else beyond the existing tests, so I’d appreciate your review and feedback before proceeding further.

@edison1105 edison1105 linked an issue Jul 16, 2025 that may be closed by this pull request
@edison1105 edison1105 moved this to Vapor in Next Minor Jul 16, 2025
})
})

describe('asset imports', () => {
Copy link
Member

Choose a reason for hiding this comment

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

A new test file should be created to test assetUrl and srcset. For example:

  • templateTransformAssetUrl.spec.ts
  • templateTransformSrcset.spec.ts

Try to port the relevant test cases from the existing templateTransformAssetUrl.spec.ts and templateTransformSrcset.spec.ts.

@ShenQingchuan
Copy link

The current implementation of this PR still has the following issues:

  1. The template string parameter within the generated _template(...) template creation has an incorrect implementation. It converts to _template(``<img src="" + _imports_0 + "" alt="..." >``), which breaks the src attribute's value.

  2. Currently, transformNativeElement has a fundamental problem:

interface IREffect {
  // Here, `expressions` was previously considered to only be `SimpleExpressionNode` in its type.
  expressions: (SimpleExpressionNode | CompoundExpressionNode)[]
  operations: OperationNode[]
}

Therefore, for srcset's multiple import string variable concatenating operations, it cannot be properly parsed and recognized, leading to it ultimately being classified as a dynamic expression and thus unable to be statically hoisted.

Thus, transformNativeElement needs to categorize and discuss the expression types to determine whether they can be statically hoisted as a whole:

  • simple expression / string / symbol = can be directly hoisted
  • compound expression = recursive judgment
  • interpolation expression = judge whether the interpolated expression can be hoisted

@Gianthard-cyh
Copy link
Author

Thanks for your response @ShenQingchuan! I’ve also encountered this with assetURLs. Since IRProp is currently typed to only accept SimpleExpressionNode:

export interface IRProp extends Omit<DirectiveTransformResult, 'value'> {
  values: SimpleExpressionNode[]
}

…it becomes tricky to support cases like:

<use href="~@svg/file.svg#fragment"></use>

In this case, the prop value is actually _imports_0 + '#fragment', but it’s wrapped as a single SimpleExpressionNode, even though it’s clearly a compound expression. This makes it difficult to correctly extract or manipulate the individual parts, especially for asset URL resolution.

I’m currently trying to work around this, though it’s a bit challenging for me.

@Gianthard-cyh Gianthard-cyh requested a review from edison1105 July 18, 2025 15:53
@netlify
Copy link

netlify bot commented Oct 20, 2025

Deploy Preview for vue-sfc-playground failed. Why did it fail? →

Name Link
🔨 Latest commit 079bc73
🔍 Latest deploy log https://app.netlify.com/projects/vue-sfc-playground/deploys/68f6f53782d18600088043c8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Vapor

Development

Successfully merging this pull request may close these issues.

[Vapor] Using image from public directory causes error

3 participants