From 8b5c058e229e4713671943842a6c50e4108e207d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Thu, 11 Sep 2025 14:02:00 +0200 Subject: [PATCH 1/3] fix tailwind skeleton --- packages/rspack/lib/config.js | 78 ++++++++++++++++++- .../static-assets/skel-tailwind/.meteorignore | 2 + .../skel-tailwind/client/main.css | 4 +- .../skel-tailwind/client/main.jsx | 1 + .../skel-tailwind/imports/ui/App.jsx | 1 - .../skel-tailwind/imports/ui/Hello.jsx | 4 +- 6 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 tools/static-assets/skel-tailwind/.meteorignore diff --git a/packages/rspack/lib/config.js b/packages/rspack/lib/config.js index 6855a291cf..e7ef58723e 100644 --- a/packages/rspack/lib/config.js +++ b/packages/rspack/lib/config.js @@ -4,6 +4,7 @@ */ import { glob } from 'glob'; import path from 'path'; +import fs from 'fs'; const { logInfo } = require('meteor/tools-core/lib/log'); const { @@ -22,6 +23,7 @@ const { isMeteorScssProject, getMeteorEnvPackageDirs, getMeteorAppConfig, + getMeteorAppDir, } = require('meteor/tools-core/lib/meteor'); const { buildUnignorePatterns } = require('meteor/tools-core/lib/ignore'); @@ -30,6 +32,53 @@ import { getInitialEntrypoints } from './build-context'; const { ensureModuleFilesExist, getBuildFilePath } = require('./build-context'); const { RSPACK_BUILD_CONTEXT, FILE_ROLE } = require('./constants'); +/** + * Checks if exact entries exist in the .meteorignore file + * @param {string[]} entries - Array of exact entries to check for + * @returns {Object} Object with keys corresponding to each entry and values as booleans + */ +function checkMeteorIgnoreExactEntries(entries) { + const meteorIgnorePath = path.join(getMeteorAppDir(), '.meteorignore'); + const results = {}; + + // Initialize results object with false for each entry + entries.forEach(entry => { + results[entry] = false; + }); + + // Check if .meteorignore file exists + if (!fs.existsSync(meteorIgnorePath)) { + return results; + } + + // Read the .meteorignore file + try { + const content = fs.readFileSync(meteorIgnorePath, 'utf8'); + const lines = content.split('\n'); + + // Check each line against all entries + lines.forEach(line => { + // Skip empty lines and comments + if (!line.trim() || line.trim().startsWith('#')) { + return; + } + + const trimmedLine = line.trim(); + + // Check for exact matches + entries.forEach(entry => { + if (trimmedLine === entry) { + results[entry] = true; + } + }); + }); + } catch (error) { + // If there's an error reading the file, return the initialized results + } + + return results; +} + /** * Gets the list of file extensions to ignore based on project type * For Blaze projects, it excludes .html as used by Blaze @@ -144,10 +193,31 @@ export function configureMeteorForRspack() { // Skip immediate html and css children from intial entrypoint contexts extraFilesToIgnore = [ ...extraFilesToIgnore, - ...initialEntrypointContexts.flatMap(entrypoint => [ - `!${entrypoint}/*.html`, - `!${entrypoint}/*.css`, - ]), + ...initialEntrypointContexts.flatMap(entrypoint => { + // Create exact entries to check for + const cssEntry = `${entrypoint}/*.css`; + const htmlEntry = `${entrypoint}/*.html`; + + // Check all entries at once + const entryResults = checkMeteorIgnoreExactEntries([cssEntry, htmlEntry]); + const hasMatchingCssEntry = entryResults[cssEntry]; + const hasMatchingHtmlEntry = entryResults[htmlEntry]; + + // Prepare the result array + const result = []; + + // Only add the HTML ignore pattern if there's no matching HTML entry in .meteorignore + if (!hasMatchingHtmlEntry) { + result.push(`!${htmlEntry}`); + } + + // Only add the CSS ignore pattern if there's no matching CSS entry in .meteorignore + if (!hasMatchingCssEntry) { + result.push(`!${cssEntry}`); + } + + return result; + }), ]; const testIgnorePath = `${RSPACK_BUILD_CONTEXT}/${path.dirname( diff --git a/tools/static-assets/skel-tailwind/.meteorignore b/tools/static-assets/skel-tailwind/.meteorignore new file mode 100644 index 0000000000..34d517a99e --- /dev/null +++ b/tools/static-assets/skel-tailwind/.meteorignore @@ -0,0 +1,2 @@ +# Ignore Meteor CSS handling; let Rspack resolve Tailwind styles +client/*.css diff --git a/tools/static-assets/skel-tailwind/client/main.css b/tools/static-assets/skel-tailwind/client/main.css index e059394a6d..6ea2603dca 100644 --- a/tools/static-assets/skel-tailwind/client/main.css +++ b/tools/static-assets/skel-tailwind/client/main.css @@ -1,6 +1,4 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import "tailwindcss"; body { padding: 10px; diff --git a/tools/static-assets/skel-tailwind/client/main.jsx b/tools/static-assets/skel-tailwind/client/main.jsx index a42cee8ff3..ea3a779300 100644 --- a/tools/static-assets/skel-tailwind/client/main.jsx +++ b/tools/static-assets/skel-tailwind/client/main.jsx @@ -2,6 +2,7 @@ import React from 'react'; import { Meteor } from 'meteor/meteor'; import { render } from 'react-dom'; import { App } from '/imports/ui/App'; +import './main.css'; Meteor.startup(() => { render(, document.getElementById('react-target')); diff --git a/tools/static-assets/skel-tailwind/imports/ui/App.jsx b/tools/static-assets/skel-tailwind/imports/ui/App.jsx index b74141276d..6cc8298b0e 100644 --- a/tools/static-assets/skel-tailwind/imports/ui/App.jsx +++ b/tools/static-assets/skel-tailwind/imports/ui/App.jsx @@ -4,7 +4,6 @@ import { Info } from './Info.jsx'; export const App = () => (
-

Welcome to Meteor!

diff --git a/tools/static-assets/skel-tailwind/imports/ui/Hello.jsx b/tools/static-assets/skel-tailwind/imports/ui/Hello.jsx index ca51ed5233..ad3ae3c053 100644 --- a/tools/static-assets/skel-tailwind/imports/ui/Hello.jsx +++ b/tools/static-assets/skel-tailwind/imports/ui/Hello.jsx @@ -13,9 +13,9 @@ export const Hello = () => {
-

+

Welcome to Meteor! -

+
From 71ebae6495b806c842d45b66dce7af3190864db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Thu, 11 Sep 2025 14:12:45 +0200 Subject: [PATCH 2/3] generalize body styles assertion to support any element --- tools/modern-tests/assertions.js | 43 ++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/tools/modern-tests/assertions.js b/tools/modern-tests/assertions.js index cf31f15aaa..4b873f6d9e 100644 --- a/tools/modern-tests/assertions.js +++ b/tools/modern-tests/assertions.js @@ -215,18 +215,40 @@ export async function assertConsoleEval(code, expectedResult, options = {}) { } /** - * Helper function to assert that the body element has the expected CSS styles + * Helper function to assert that an element has the expected CSS styles + * @param {string} selector - CSS selector string (e.g., 'body', '.my-class') or a string representing a DOM element (e.g., 'document.body') * @param {Object} expectedStyles - Expected CSS styles as key-value pairs * @param {Object} options - Additional options for assertConsoleEval * @returns {Promise} - A promise that resolves with the computed styles */ -export async function assertBodyStyles(expectedStyles, options = {}) { - console.log(`Asserting body styles: ${JSON.stringify(expectedStyles)}`); +export async function assertStyles(selector, expectedStyles, options = {}) { + // Determine if the selector is a CSS selector or a DOM element reference + const isCssSelector = selector.startsWith('.') || + selector.startsWith('#') || + selector.startsWith('[') || + selector === 'body' || + selector.includes(' '); + + console.log(`Asserting styles for ${selector}: ${JSON.stringify(expectedStyles)}`); // Create a JavaScript code string that evaluates the computed styles const code = ` (() => { - const computedStyle = getComputedStyle(document.body); + let element; + + // Handle the selector based on its type + ${isCssSelector + ? `element = document.querySelector('${selector}'); + if (!element) { + throw new Error('Element not found with selector: ${selector}'); + }` + : `element = ${selector}; + if (!element) { + throw new Error('Element not found: ${selector}'); + }` + } + + const computedStyle = getComputedStyle(element); const result = {}; ${Object.keys(expectedStyles).map(prop => `result['${prop}'] = computedStyle.getPropertyValue('${prop}');` @@ -236,12 +258,23 @@ export async function assertBodyStyles(expectedStyles, options = {}) { `; // Use assertConsoleEval to evaluate the code and check the result - return await assertConsoleEval(code, expectedStyles, { + return assertConsoleEval(code, expectedStyles, { exactMatch: false, ...options }); } +/** + * Helper function to assert that the body element has the expected CSS styles + * @param {Object} expectedStyles - Expected CSS styles as key-value pairs + * @param {Object} options - Additional options for assertConsoleEval + * @returns {Promise} - A promise that resolves with the computed styles + */ +export async function assertBodyStyles(expectedStyles, options = {}) { + // Use assertStyles with document.body as the selector + return assertStyles('document.body', expectedStyles, options); +} + /** * Helper function to assert that meta tags have the expected content * @param {Object} expectedMetaTags - Expected meta tag properties and values as key-value pairs From bff015fba892100708e97c1983f982469071d6ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Thu, 11 Sep 2025 14:32:08 +0200 Subject: [PATCH 3/3] ensure proper Tailwind styles loading test coverage --- tools/modern-tests/skeleton.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tools/modern-tests/skeleton.test.js b/tools/modern-tests/skeleton.test.js index e8adb6c15c..50591cda79 100644 --- a/tools/modern-tests/skeleton.test.js +++ b/tools/modern-tests/skeleton.test.js @@ -6,6 +6,7 @@ import { testMeteorSkeleton } from "./test-helpers"; +import { assertStyles } from "./assertions"; describe('Meteor Skeletons /', () => { describe('Apollo Skeleton /', testMeteorSkeleton({ @@ -87,6 +88,20 @@ describe('Meteor Skeletons /', () => { server: 'server/main.ts', test: 'tests/main.ts', }, + customAssertions: { + afterRun: async ({ port }) => { + // Verify Tailwind styles for ".bg-gray-100" element + await assertStyles('.bg-gray-100', { + ['background-color']: 'oklch(0.967 0.003 264.542)', + }); + }, + afterRunProduction: async ({ port }) => { + // Verify Tailwind styles for ".bg-gray-100" element + await assertStyles('.bg-gray-100', { + ['background-color']: 'lab(96.1596 -0.0823438 -1.13575)', + }); + } + } })); describe('Typescript Skeleton /', testMeteorSkeleton({