support assets automatic resolution to public folder and test coverage several scenarios

This commit is contained in:
Nacho Codoñer
2025-12-15 17:22:24 +01:00
parent d1d3268527
commit 8e8364dca6
26 changed files with 150 additions and 28 deletions

View File

@@ -1,12 +1,12 @@
{
"name": "@meteorjs/rspack",
"version": "0.2.54",
"version": "0.3.50",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@meteorjs/rspack",
"version": "0.2.54",
"version": "0.3.50",
"license": "ISC",
"dependencies": {
"fast-deep-equal": "^3.1.3",
@@ -3251,7 +3251,7 @@
}
},
"node_modules/media-typer": {
"version": "0.3.0",
"version": "0.3.50",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
{
"name": "@meteorjs/rspack",
"version": "0.2.54",
"version": "0.3.50",
"description": "Configuration logic for using Rspack in Meteor projects",
"main": "index.js",
"type": "commonjs",

View File

@@ -5,7 +5,7 @@
export const DEFAULT_RSPACK_VERSION = '1.6.5';
export const DEFAULT_METEOR_RSPACK_VERSION = '0.2.54';
export const DEFAULT_METEOR_RSPACK_VERSION = '0.3.50';
export const DEFAULT_METEOR_RSPACK_REACT_HMR_VERSION = '1.4.3';

View File

@@ -1,4 +0,0 @@
body {
padding: 10px;
font-family: sans-serif;
}

View File

@@ -1,11 +1,17 @@
import imagePublic from '@public/1x1-public.jpg';
import React from 'react';
import './main.css';
import { Hello } from './Hello.jsx';
import { Info } from './Info.jsx';
import imageGenerated from './images/1x1-js.png';
export const App = () => (
<div>
<h1>Welcome to Meteor!</h1>
<Hello/>
<Info/>
<Hello />
<Info />
<img id="image-generated" src={imageGenerated} alt="1x1 pixel imported in JS" />
<img id="image-public" src={imagePublic} alt="1x1 pixel imported in JS" />
</div>
);

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

View File

@@ -0,0 +1,9 @@
body {
padding: 10px;
font-family: sans-serif;
background-image: url('/1x1-css.png');
}
h1 {
background-image: url('@public/1x1-public.jpg');
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

View File

@@ -0,0 +1,36 @@
const { defineConfig } = require('@meteorjs/rspack');
const path = require('path');
/**
* Rspack configuration for Meteor projects.
*
* Provides typed flags on the `Meteor` object, such as:
* - `Meteor.isClient` / `Meteor.isServer`
* - `Meteor.isDevelopment` / `Meteor.isProduction`
* - …and other flags available
*
* Use these flags to adjust your build settings based on environment.
*/
module.exports = defineConfig(Meteor => {
return {
resolve: {
alias: {
"@public": path.resolve(__dirname, "public"),
},
},
module: {
rules: [
// ✅ Images
{
test: /\.(png|jpe?g|gif|webp|avif)$/i,
type: "asset/resource", // emits a file, returns URL string
},
// (optional) SVGs
{
test: /\.svg$/i,
type: "asset/resource",
},
],
},
};
});

View File

@@ -17,7 +17,7 @@
"vue-router": "^4.2.5"
},
"devDependencies": {
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@rspack/cli": "^1.4.8",
"@rspack/core": "^1.4.8",
"@tailwindcss/postcss": "^4.1.12",

View File

@@ -9,7 +9,7 @@ import {
import { testMeteorBundler, testMeteorRspackBundler } from './test-helpers';
import fs from 'fs-extra';
import path from 'path';
import { assertMeteorReactApp } from "./assertions";
import { assertMeteorReactApp, assertConsoleEval } from "./assertions";
describe('React App Bundling /', () => {
@@ -72,9 +72,13 @@ describe('React App Bundling /', () => {
server: 'server/main.js',
test: 'tests/main.js'
},
configFile: 'rspack.config.cjs',
customAssertions: {
afterRun: async ({ result }) => {
await waitForReactEnvs(result.outputLines, { isJsxEnabled: true });
// Check if images exist and return 200 status code
await assertImagesExistAndLoad();
},
afterRunRebuildClient: async ({ allConsoleLogs }) => {
// Check for HMR output as enabled by default
@@ -82,6 +86,9 @@ describe('React App Bundling /', () => {
},
afterRunProduction: async ({ result }) => {
await waitForReactEnvs(result.outputLines, { isJsxEnabled: true });
// Check if images exist and return 200 status code
await assertImagesExistAndLoad();
},
afterRunProductionRebuildClient: async ({ allConsoleLogs }) => {
// Check for HMR to not be enabled in production-like mode
@@ -122,3 +129,71 @@ export async function waitForReactEnvs(outputLines, options = {}) {
);
}
}
/**
* Helper function to assert that images exist in the DOM and return 200 status code when fetched
* @returns {Promise<void>} - A promise that resolves when images are verified
*/
export async function assertImagesExistAndLoad() {
await assertConsoleEval(`
(async () => {
// Get the image elements
const imageGenerated = document.getElementById('image-generated');
const imagePublic = document.getElementById('image-public');
// Check if images exist
if (!imageGenerated || !imagePublic) {
return { success: false, error: 'Images not found in the DOM' };
}
// Function to check if an image URL returns 200
const checkImageStatus = async (url) => {
try {
const response = await fetch(url);
return {
url,
status: response.status,
ok: response.ok
};
} catch (error) {
return {
url,
status: 0,
ok: false,
error: error.message
};
}
};
// Function to extract URL from background-image CSS property
const extractUrlFromBackgroundImage = (backgroundImage) => {
// Extract the URL from the background-image property (format: url("..."))
const urlMatch = backgroundImage.match(/url\\(['"]?([^'"\\)]+)['"]?\\)/);
return urlMatch ? urlMatch[1] : null;
};
// Get body's background-image
const bodyStyle = getComputedStyle(document.body);
const backgroundImage = bodyStyle.backgroundImage;
const backgroundImageUrl = extractUrlFromBackgroundImage(backgroundImage);
// Check both images and background image
const generatedResult = await checkImageStatus(imageGenerated.src);
const publicResult = await checkImageStatus(imagePublic.src);
let backgroundResult = { ok: true };
if (backgroundImageUrl) {
backgroundResult = await checkImageStatus(backgroundImageUrl);
} else {
backgroundResult = {
ok: false,
error: 'No background image URL found on body element'
};
}
return {
success: generatedResult.ok && publicResult.ok && backgroundResult.ok,
};
})()
`, { success: true }, { exactMatch: false });
}

View File

@@ -22,7 +22,7 @@
},
"devDependencies": {
"@angular/compiler-cli": "^20.0.0",
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@nx/angular-rspack": "^21.1.0",
"@rsdoctor/rspack-plugin": "^1.2.3",
"@rspack/cli": "^1.6.5",

View File

@@ -20,7 +20,7 @@
"devDependencies": {
"@graphql-tools/webpack-loader": "^7.0.0",
"@rsdoctor/rspack-plugin": "^1.2.3",
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@rspack/cli": "^1.6.5",
"@rspack/core": "^1.6.5",
"@rspack/plugin-react-refresh": "^1.4.3",

View File

@@ -17,7 +17,7 @@
"devDependencies": {
"@babel/preset-env": "^7.28.3",
"@babel/preset-react": "^7.23.3",
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@rsdoctor/rspack-plugin": "^1.2.3",
"@rspack/cli": "^1.6.5",
"@rspack/core": "^1.6.5",

View File

@@ -14,7 +14,7 @@
"meteor-node-stubs": "^1.2.12"
},
"devDependencies": {
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@rsdoctor/rspack-plugin": "^1.2.3",
"@rspack/cli": "^1.6.5",
"@rspack/core": "^1.6.5",

View File

@@ -21,7 +21,7 @@
"react-dom": "^18.2.0"
},
"devDependencies": {
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@rsdoctor/rspack-plugin": "^1.2.3",
"@rspack/cli": "^1.6.5",
"@rspack/core": "^1.6.5",

View File

@@ -15,7 +15,7 @@
"react-dom": "^18.2.0"
},
"devDependencies": {
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@rsdoctor/rspack-plugin": "^1.2.3",
"@rspack/cli": "^1.6.5",
"@rspack/core": "^1.6.5",

View File

@@ -12,7 +12,7 @@
"meteor-node-stubs": "^1.2.12"
},
"devDependencies": {
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@rsdoctor/rspack-plugin": "^1.2.3",
"@rspack/cli": "^1.6.5",
"@rspack/core": "^1.6.5",

View File

@@ -15,7 +15,7 @@
"react-dom": "^18.2.0"
},
"devDependencies": {
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@rsdoctor/rspack-plugin": "^1.2.3",
"@rspack/cli": "^1.6.5",
"@rspack/core": "^1.6.5",

View File

@@ -14,7 +14,7 @@
"picocolors": "^1.1.1"
},
"devDependencies": {
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@rsdoctor/rspack-plugin": "^1.2.3",
"@rspack/cli": "^1.6.5",
"@rspack/core": "^1.6.5",

View File

@@ -13,7 +13,7 @@
"meteor-node-stubs": "^1.2.12"
},
"devDependencies": {
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@rsdoctor/rspack-plugin": "^1.2.3",
"@rspack/cli": "^1.6.5",
"@rspack/core": "^1.6.5",

View File

@@ -16,7 +16,7 @@
"react-dom": "^17.0.2"
},
"devDependencies": {
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@rsdoctor/rspack-plugin": "^1.2.3",
"@rspack/cli": "^1.6.5",
"@rspack/core": "^1.6.5",

View File

@@ -15,7 +15,7 @@
"react-dom": "^18.2.0"
},
"devDependencies": {
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@rsdoctor/rspack-plugin": "^1.2.3",
"@rspack/cli": "^1.6.5",
"@rspack/core": "^1.6.5",

View File

@@ -17,7 +17,7 @@
"vue-router": "^4.2.5"
},
"devDependencies": {
"@meteorjs/rspack": "^0.2.54",
"@meteorjs/rspack": "^0.3.50",
"@rsdoctor/rspack-plugin": "^1.2.3",
"@rspack/cli": "^1.6.5",
"@rspack/core": "^1.6.5",

View File

@@ -104,7 +104,7 @@ If you find any issues, please report them to the [Meteor issues tracker](https:
- minifier-js@3.1.0-rc340.1
- minimongo@2.0.5-rc340.1
- mongo@2.2.0-rc340.1
- react-fast-refresh@0.3.0-rc340.1
- react-fast-refresh@0.3.50-rc340.1
- rspack@1.0.0-rc340.1
- shell-server@0.7.0-rc340.1
- standard-minifier-css@1.10.0-rc340.1
@@ -119,7 +119,7 @@ If you find any issues, please report them to the [Meteor issues tracker](https:
#### Bumped NPM Packages
- @meteorjs/rspack@0.2.54
- @meteorjs/rspack@0.3.50
#### Special thanks to