diff --git a/packages/playground/backend-integration/__tests__/backend-integration.spec.ts b/packages/playground/backend-integration/__tests__/backend-integration.spec.ts
new file mode 100644
index 00000000000000..3251bd0635796d
--- /dev/null
+++ b/packages/playground/backend-integration/__tests__/backend-integration.spec.ts
@@ -0,0 +1,28 @@
+import { isBuild, readManifest } from '../../testUtils'
+
+const outerAssetMatch = isBuild
+ ? /\/dev\/assets\/logo\.\w{8}\.png/
+ : /\/dev\/@fs\/.+?\/images\/logo\.png/
+
+test('should have no 404s', () => {
+ browserLogs.forEach((msg) => {
+ expect(msg).not.toMatch('404')
+ })
+})
+
+describe('asset imports from js', () => {
+ test('file outside root', async () => {
+ expect(
+ await page.textContent('.asset-reference.outside-root .asset-url')
+ ).toMatch(outerAssetMatch)
+ })
+})
+
+if (isBuild) {
+ test('manifest', async () => {
+ const manifest = readManifest('dev')
+ const htmlEntry = manifest['index.html']
+ expect(htmlEntry.css.length).toEqual(1)
+ expect(htmlEntry.assets.length).toEqual(1)
+ })
+}
diff --git a/packages/playground/backend-integration/frontend/entrypoints/global.css b/packages/playground/backend-integration/frontend/entrypoints/global.css
new file mode 100644
index 00000000000000..3ea5728368521d
--- /dev/null
+++ b/packages/playground/backend-integration/frontend/entrypoints/global.css
@@ -0,0 +1,28 @@
+@import '~/styles/background.css';
+@import '../../references.css';
+
+html, body {
+ font-family: sans-serif;
+ line-height: 2.4rem;
+}
+
+body {
+ margin: 4vh auto;
+ max-width: 800px;
+ padding: 0 4vw;
+}
+
+ul {
+ padding: 0 .4em;
+ margin: 0;
+}
+
+li {
+ display: flex;
+ align-items: center;
+}
+
+img {
+ height: 32px;
+ width: 32px;
+}
diff --git a/packages/playground/backend-integration/frontend/entrypoints/index.html b/packages/playground/backend-integration/frontend/entrypoints/index.html
new file mode 100644
index 00000000000000..3b8dedb4ac3096
--- /dev/null
+++ b/packages/playground/backend-integration/frontend/entrypoints/index.html
@@ -0,0 +1,51 @@
+
+
+
+
+
Backend Integration
+
+
+ This test configures the root
to simulate a Laravel/Rails setup.
+
+
+JS Asset References
+
+
+
+CSS Asset References
+
+
+ -
+ Background URL with Alias:
+
+
+ -
+ Background URL with Relative Path:
+
+
+
+
+
diff --git a/packages/playground/backend-integration/frontend/images/logo.png b/packages/playground/backend-integration/frontend/images/logo.png
new file mode 100644
index 00000000000000..1b3356a746b8bb
Binary files /dev/null and b/packages/playground/backend-integration/frontend/images/logo.png differ
diff --git a/packages/playground/backend-integration/frontend/styles/background.css b/packages/playground/backend-integration/frontend/styles/background.css
new file mode 100644
index 00000000000000..a6cc929f859c52
--- /dev/null
+++ b/packages/playground/backend-integration/frontend/styles/background.css
@@ -0,0 +1,15 @@
+.background-asset {
+ background-repeat: no-repeat;
+ background-size: 100%;
+ display: inline-block;
+ height: 32px;
+ width: 32px;
+}
+
+.outside-root--aliased {
+ background-image: url('~/images/logo.png');
+}
+
+.outside-root--relative {
+ background-image: url('../images/logo.png');
+}
diff --git a/packages/playground/backend-integration/package.json b/packages/playground/backend-integration/package.json
new file mode 100644
index 00000000000000..ac268b3e508739
--- /dev/null
+++ b/packages/playground/backend-integration/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "test-backend-integration",
+ "private": true,
+ "version": "0.0.0",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "debug": "node --inspect-brk ../../vite/bin/vite",
+ "serve": "vite preview"
+ }
+}
diff --git a/packages/playground/backend-integration/references.css b/packages/playground/backend-integration/references.css
new file mode 100644
index 00000000000000..3600be7cbb2f6f
--- /dev/null
+++ b/packages/playground/backend-integration/references.css
@@ -0,0 +1,11 @@
+.asset-reference {
+ display: grid;
+ grid-template-areas:
+ "summary preview ."
+ "url url url";
+}
+
+.asset-url {
+ grid-area: url;
+ white-space: nowrap;
+}
diff --git a/packages/playground/backend-integration/vite.config.js b/packages/playground/backend-integration/vite.config.js
new file mode 100644
index 00000000000000..ffbbd1a76745e0
--- /dev/null
+++ b/packages/playground/backend-integration/vite.config.js
@@ -0,0 +1,46 @@
+const path = require('path')
+const glob = require('fast-glob')
+const normalizePath = require('vite').normalizePath
+
+/**
+ * @returns {import('vite').Plugin}
+ */
+function BackendIntegrationExample() {
+ return {
+ name: 'backend-integration',
+ config() {
+ const projectRoot = __dirname
+ const sourceCodeDir = path.join(projectRoot, 'frontend')
+ const root = path.join(sourceCodeDir, 'entrypoints')
+ const outDir = path.relative(root, path.join(projectRoot, 'dist/dev'))
+
+ const entrypoints = glob
+ .sync(`${normalizePath(root)}/**/*`, { onlyFiles: true })
+ .map((filename) => [path.relative(root, filename), filename])
+
+ return {
+ build: {
+ manifest: true,
+ outDir,
+ rollupOptions: {
+ input: Object.fromEntries(entrypoints)
+ }
+ },
+ root,
+ resolve: {
+ alias: {
+ '~': sourceCodeDir
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * @returns {import('vite').UserConfig}
+ */
+module.exports = {
+ base: '/dev/',
+ plugins: [BackendIntegrationExample()]
+}