mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
support modules config to allow load in Meteor specific files or folders for plugins to act
This commit is contained in:
@@ -21,7 +21,9 @@ const {
|
||||
isMeteorLessProject,
|
||||
isMeteorScssProject,
|
||||
getMeteorEnvPackageDirs,
|
||||
getMeteorAppConfig,
|
||||
} = require('meteor/tools-core/lib/meteor');
|
||||
const { buildUnignorePatterns } = require('meteor/tools-core/lib/ignore');
|
||||
|
||||
import { getInitialEntrypoints } from './build-context';
|
||||
|
||||
@@ -92,6 +94,7 @@ function getFileExtensionsToIgnore() {
|
||||
* @returns {void}
|
||||
*/
|
||||
export function configureMeteorForRspack() {
|
||||
const meteorAppConfig = getMeteorAppConfig();
|
||||
const initialEntrypoints = getInitialEntrypoints();
|
||||
|
||||
// Ignore node_modules to prevent Meteor from processing them
|
||||
@@ -180,9 +183,13 @@ export function configureMeteorForRspack() {
|
||||
),
|
||||
];
|
||||
const filesToIgnore = [...rootFilesToIgnore, ...extraFilesToIgnore];
|
||||
const unignoredFilesAndFolders = buildUnignorePatterns(
|
||||
meteorAppConfig?.modules || [],
|
||||
{ skipLevel: 1 },
|
||||
);
|
||||
const meteorAppIgnores = `${foldersToIgnore.join(' ')} ${filesToIgnore.join(
|
||||
' ',
|
||||
)}`;
|
||||
)} ${unignoredFilesAndFolders.join(' ')}`.trim();
|
||||
setMeteorAppIgnore(meteorAppIgnores);
|
||||
|
||||
if (isMeteorAppDebug() || isMeteorAppConfigModernVerbose()) {
|
||||
|
||||
87
packages/tools-core/lib/ignore.js
Normal file
87
packages/tools-core/lib/ignore.js
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Build gitignore-style "unignore" patterns for specific files/folders.
|
||||
*
|
||||
* Rules:
|
||||
* - Files: !a/ !a/b/ !a/b/c.txt
|
||||
* - Folders (must end with '/'):
|
||||
* !a/ !a/b/ !a/b/c/ !a/b/c/**
|
||||
*
|
||||
* @param {string[]} inputPaths Paths to keep. Use '/' for dirs (e.g. 'assets/public/').
|
||||
* @param {Object} [options]
|
||||
* @param {boolean} [options.includeAllAncestors=true] If false, only include the immediate parent dir.
|
||||
* @param {boolean} [options.includeGlobForDirs=true] Emit '**' for directories.
|
||||
* @param {number} [options.skipLevel=0] Skip this many levels from the beginning.
|
||||
* @returns {string[]} Negation patterns, in correct order.
|
||||
*/
|
||||
export function buildUnignorePatterns(inputPaths, {
|
||||
includeAllAncestors = true,
|
||||
includeGlobForDirs = true,
|
||||
skipLevel = 0,
|
||||
} = {}) {
|
||||
const out = [];
|
||||
const seen = new Set();
|
||||
|
||||
const push = (p) => {
|
||||
if (!seen.has(p)) {
|
||||
seen.add(p);
|
||||
out.push(p);
|
||||
}
|
||||
};
|
||||
|
||||
for (let raw of inputPaths) {
|
||||
if (!raw || typeof raw !== 'string') continue;
|
||||
|
||||
// Normalize: forward slashes, drop leading './', collapse double slashes
|
||||
let anchored = raw.startsWith('/');
|
||||
let p = raw.replace(/\\/g, '/')
|
||||
.replace(/^\.\/+/, '')
|
||||
.replace(/\/{2,}/g, '/');
|
||||
|
||||
// detect dir by trailing slash
|
||||
const isDir = p.endsWith('/');
|
||||
// strip leading + trailing slashes for splitting, but remember anchoring
|
||||
const core = p.replace(/^\/+/, '').replace(/\/+$/, '');
|
||||
if (!core) continue;
|
||||
|
||||
const parts = core.split('/');
|
||||
|
||||
// Process based on skipLevel
|
||||
if (skipLevel >= parts.length) {
|
||||
// Skip everything if skipLevel is greater than or equal to the number of parts
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ancestors (top-down)
|
||||
if (includeAllAncestors) {
|
||||
// Start from skipLevel + 1 to skip the specified number of levels
|
||||
const startLevel = Math.max(1, skipLevel + 1);
|
||||
for (let i = startLevel; i <= parts.length - 1; i++) {
|
||||
const anc = (anchored ? '/' : '') + parts.slice(0, i).join('/') + '/';
|
||||
push('!' + anc);
|
||||
}
|
||||
} else if (parts.length > 1) {
|
||||
// Only immediate parent
|
||||
// For minimal mode with skipLevel, we need to check if the parent is at a level we should skip
|
||||
if (skipLevel < parts.length - 1) {
|
||||
// Check if the parent's level is greater than skipLevel
|
||||
const parentLevel = parts.length - 1;
|
||||
if (parentLevel > skipLevel) {
|
||||
const parent = (anchored ? '/' : '') + parts.slice(0, parts.length - 1).join('/') + '/';
|
||||
push('!' + parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the file/directory pattern
|
||||
if (isDir) {
|
||||
const dir = (anchored ? '/' : '') + parts.join('/') + '/';
|
||||
push('!' + dir);
|
||||
if (includeGlobForDirs) push('!' + dir + '**');
|
||||
} else {
|
||||
const file = (anchored ? '/' : '') + parts.join('/');
|
||||
push('!' + file);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -5,3 +5,4 @@ export * from './lib/process';
|
||||
export * from './lib/global-state';
|
||||
export * from './lib/git';
|
||||
export * from './lib/string';
|
||||
export * from './lib/ignore';
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"client": "client/main.jsx",
|
||||
"server": "server/main.js"
|
||||
},
|
||||
"modules": ["styles/module.css"],
|
||||
"modern": true
|
||||
}
|
||||
}
|
||||
|
||||
3
tools/modern-tests/apps/react-router/styles/module.css
Normal file
3
tools/modern-tests/apps/react-router/styles/module.css
Normal file
@@ -0,0 +1,3 @@
|
||||
body {
|
||||
align-content: center;
|
||||
}
|
||||
@@ -167,6 +167,7 @@ export async function assertConsoleEval(code, expectedResult, options = {}) {
|
||||
try {
|
||||
// Evaluate the code in the browser context
|
||||
const result = await page.evaluate(code);
|
||||
console.log("--> (assertions.js-Line: 170)\n result: ", result);
|
||||
|
||||
if (exactMatch) {
|
||||
// Check for exact match
|
||||
|
||||
@@ -27,6 +27,10 @@ describe('ReactRouter App Bundling /', () => {
|
||||
await assertBodyStyles({
|
||||
'white-space': 'break-spaces',
|
||||
});
|
||||
// Meteor modules config
|
||||
await assertBodyStyles({
|
||||
'align-content': 'center',
|
||||
});
|
||||
// Custom html rspack plugin options
|
||||
await assertMetaTags({
|
||||
'theme-color': '#4285f4',
|
||||
@@ -50,6 +54,10 @@ describe('ReactRouter App Bundling /', () => {
|
||||
await assertBodyStyles({
|
||||
'white-space': 'break-spaces',
|
||||
});
|
||||
// Meteor modules config
|
||||
await assertBodyStyles({
|
||||
'align-content': 'center',
|
||||
});
|
||||
// Custom html rspack plugin options
|
||||
await assertMetaTags({
|
||||
'theme-color': '#4285f4',
|
||||
|
||||
@@ -174,6 +174,20 @@ Ensure your app defines these entry files with the correct paths where each modu
|
||||
|
||||
Defining entry points improves performance even with the Meteor bundler, as Meteor stops scanning and eagerly loading unnecessary files. For Meteor-Rspack integration, this is required, since it does not support automatic code discovery for efficiency.
|
||||
|
||||
In Meteor-Rspack integration, all app code is ignored by Meteor and handled by Rspack. By default, Meteor still processes eagerly CSS and HTML files in the entry folder (e.g. `client/`).
|
||||
|
||||
If you need Meteor to handle CSS or HTML files outside the main entry folder, add them to the `modules` field. This field accepts an array of strings, each pointing to a file or folder, except those inside the reserved `imports` folder for scripts.
|
||||
|
||||
``` json
|
||||
{
|
||||
"meteor": {
|
||||
"modules": ["styles/main.css"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With this, Meteor will process these files, merge stylesheets, generate the final HTML, and support files a Meteor plugin may use, except for JS or script code now handled by Rspack. You can also process CSS and HTML files directly with Rspack using loaders from imports in your app code, as mentioned in ["CSS, Less and SCSS"](#css-less-and-scss) or ["HtmlRspackPlugin"](#htmlrspackplugin). If you prefer Meteor's loading approach, you can still rely on it.
|
||||
|
||||
### Nested Imports
|
||||
|
||||
Nested imports are a feature of Meteor’s bundler, not supported in standard bundlers. Meteor introduced them during a time when bundling standards were still evolving and experimented with its own approach. This feature comes from the [`reify` module](https://github.com/benjamn/reify/tree/main) and works with Babel transpilation. SWC doesn't support them since they were never standardized.
|
||||
|
||||
Reference in New Issue
Block a user