add Babel project setup on test suite with rspack.config.js overrides

This commit is contained in:
Nacho Codoñer
2025-08-14 15:39:56 +02:00
parent c862ed7ef9
commit 9ee02f4175
23 changed files with 3822 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
["module-resolver", {
"alias": {
"@ui": "./imports/ui",
"@api": "./imports/api"
}
}]
]
}

View File

@@ -0,0 +1 @@
node_modules/

View File

@@ -0,0 +1 @@
local

View File

@@ -0,0 +1,7 @@
# This file contains a token that is unique to your project.
# Check it into your repository along with the rest of this directory.
# It can be used for purposes such as:
# - ensuring you don't accidentally deploy one app on top of another
# - providing package authors with aggregated statistics
yhlwvsq0co1.ensn1rspode

View File

@@ -0,0 +1,22 @@
# Meteor packages used by this project, one per line.
# Check this file (and the other files in this directory) into your repository.
#
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.
meteor-base # Packages every Meteor app needs to have
mobile-experience # Packages for a great mobile UX
mongo # The database Meteor supports right now
reactive-var # Reactive variable for tracker
standard-minifier-css # CSS minifier run for production mode
standard-minifier-js # JS minifier run for production mode
es5-shim # ECMAScript 5 compatibility for older browsers
ecmascript # Enable ECMAScript2015+ syntax in app code
typescript # Enable TypeScript syntax in .ts and .tsx modules
shell-server # Server-side component of the `meteor shell` command
hot-module-replacement # Update client in development without reloading the page
static-html # Define static page content in .html files
apollo # Basic Apollo integration for Meteor apps
compat:graphql # Import .graphql files

View File

@@ -0,0 +1,2 @@
server
browser

View File

@@ -0,0 +1 @@
none

View File

@@ -0,0 +1,73 @@
accounts-base@3.1.1
allow-deny@2.1.0
apollo@5.0.1-beta.0
autoupdate@2.0.1
babel-compiler@7.12.1
babel-runtime@1.5.2
base64@1.0.13
binary-heap@1.0.12
boilerplate-generator@2.0.1
caching-compiler@2.0.1
callback-hook@1.6.1
check@1.4.4
compat:graphql@2.0.0
core-runtime@1.0.0
ddp@1.4.2
ddp-client@3.1.1
ddp-common@1.4.4
ddp-rate-limiter@1.2.2
ddp-server@3.1.2
diff-sequence@1.1.3
dynamic-import@0.7.4
ecmascript@0.16.12
ecmascript-runtime@0.8.3
ecmascript-runtime-client@0.12.3
ecmascript-runtime-server@0.11.1
ejson@1.1.5
es5-shim@4.8.1
facts-base@1.0.2
fetch@0.1.6
geojson-utils@1.0.12
hot-code-push@1.0.5
hot-module-replacement@0.5.4
id-map@1.2.0
inter-process-messaging@0.1.2
launch-screen@2.0.1
localstorage@1.2.1
logging@1.3.6
meteor@2.1.1
meteor-base@1.5.2
minifier-css@2.0.1
minifier-js@3.0.3
minimongo@2.0.3
mobile-experience@1.1.2
mobile-status-bar@1.1.1
modern-browsers@0.2.3
modules@0.20.3
modules-runtime@0.13.2
modules-runtime-hot@0.14.3
mongo@2.1.3
mongo-decimal@0.2.0
mongo-dev-server@1.1.1
mongo-id@1.0.9
npm-mongo@6.16.0
ordered-dict@1.2.0
promise@1.0.0
random@1.2.2
rate-limit@1.1.2
react-fast-refresh@0.2.9
reactive-var@1.0.13
reload@1.3.2
retry@1.1.1
routepolicy@1.1.2
shell-server@0.6.1
socket-stream-client@0.6.1
standard-minifier-css@1.9.3
standard-minifier-js@3.1.1
static-html@1.4.0
static-html-tools@1.0.0
tracker@1.3.4
typescript@5.6.5
url@1.3.5
webapp@2.0.7
webapp-hashing@1.1.2

View File

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

View File

@@ -0,0 +1,8 @@
<head>
<title>babel</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="react-target"></div>
</body>

View File

@@ -0,0 +1,10 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
import { Meteor } from 'meteor/meteor';
import { App } from '/imports/ui/App';
Meteor.startup(() => {
const container = document.getElementById('react-target');
const root = createRoot(container);
root.render(<App />);
});

View File

@@ -0,0 +1,3 @@
import { Mongo } from 'meteor/mongo';
export const LinksCollection = new Mongo.Collection('links');

View File

@@ -0,0 +1,10 @@
type Link {
_id: ID!
title: String
url: String
}
type Query {
getLink (id: ID!): Link
getLinks: [Link]
}

View File

@@ -0,0 +1,30 @@
import React from 'react';
import { InMemoryCache, ApolloProvider, ApolloClient, ApolloLink, HttpLink } from '@apollo/client';
// import { MeteorAccountsLink } from 'meteor/apollo'
import { Hello } from './Hello.jsx';
import { Info } from './Info.jsx';
const cache = new InMemoryCache().restore(window.__APOLLO_STATE__);
const link = ApolloLink.from([
// MeteorAccountsLink(),
new HttpLink({
uri: '/graphql'
})
]);
const client = new ApolloClient({
uri: '/graphql',
cache,
link,
});
export const App = () => (
<ApolloProvider client={client}>
<div>
<h1>Welcome to Meteor! </h1>
<Hello/>
<Info/>
</div>
</ApolloProvider>
);

View File

@@ -0,0 +1,16 @@
import React, { useState } from 'react';
export const Hello = () => {
const [counter, setCounter] = useState(0);
const increment = () => {
setCounter(counter + 1);
};
return (
<div>
<button onClick={increment}>Click Me</button>
<p>You've pressed the button {counter} times.</p>
</div>
);
};

View File

@@ -0,0 +1,30 @@
import React from 'react';
import { useQuery, gql } from '@apollo/client';
const GET_LINKS = gql`
{
links: getLinks {
_id
title
url
}
}
`;
export const Info = () => {
const { loading, error, data } = useQuery(GET_LINKS);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error </p>;
return (
<div>
<h2>Learn Meteor!</h2>
<ul>{data?.links?.map(
link => <li key={link._id}>
<a href={link.url} target="_blank">{link.title}</a>
</li>
)}</ul>
</div>
);
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,36 @@
{
"name": "babel",
"private": true,
"scripts": {
"start": "meteor run --open",
"test": "meteor test --once --driver-package meteortesting:mocha",
"test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
"visualize": "meteor --production --extra-packages bundle-visualizer"
},
"dependencies": {
"@apollo/client": "^3.9.2",
"@apollo/server": "^4.10.0",
"@babel/runtime": "^7.23.9",
"@swc/helpers": "^0.5.17",
"graphql": "^16.8.1",
"meteor-node-stubs": "^1.2.12",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@babel/preset-env": "^7.28.3",
"@babel/preset-react": "^7.23.3",
"babel-loader": "^9.1.3",
"babel-plugin-module-resolver": "^5.0.0",
"playwright": "^1.54.2",
"webpack-graphql-loader": "^1.0.2"
},
"meteor": {
"mainModule": {
"client": "client/main.jsx",
"server": "server/main.js"
},
"testModule": "tests/main.js",
"modern": true
}
}

View File

@@ -0,0 +1,32 @@
import { defineConfig } from '@meteorjs/rspack';
/**
* 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.
*/
export default defineConfig(Meteor => {
return {
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules|\.meteor\/local/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.(graphql|gql)$/,
exclude: /node_modules/,
loader: 'webpack-graphql-loader',
},
],
},
};
});

View File

@@ -0,0 +1,35 @@
import { ApolloServer } from '@apollo/server';
import { WebApp, WebAppInternals } from 'meteor/webapp';
import { getUser } from 'meteor/apollo';
import { LinksCollection } from '/imports/api/links';
import typeDefs from '/imports/apollo/schema.graphql';
import { expressMiddleware } from '@apollo/server/express4';
const express = WebAppInternals.NpmModules.express.module;
const resolvers = {
Query: {
getLink: async (obj, { id }) => LinksCollection.findOneAsync(id),
getLinks: async () => LinksCollection.find().fetchAsync()
}
};
const context = async ({ req }) => ({
user: await getUser(req.headers.authorization)
});
const server = new ApolloServer({
cache: 'bounded',
typeDefs,
resolvers,
});
export async function startApolloServer() {
await server.start();
WebApp.handlers.use(
'/graphql', // Configure the path as you want.
express.json(),
expressMiddleware(server, { context }) // From `@apollo/server/express4`
);
}

View File

@@ -0,0 +1,39 @@
import { Meteor } from 'meteor/meteor';
import { LinksCollection } from '/imports/api/links';
import { startApolloServer } from './apollo';
async function insertLink({ title, url }) {
await LinksCollection.insertAsync({ title, url, createdAt: new Date() });
}
try {
startApolloServer().then();
} catch (e) {
console.error(e.reason);
}
Meteor.startup(async () => {
// If the Links collection is empty, add some data.
if (await LinksCollection.find().countAsync() === 0) {
await insertLink({
title: 'Do the Tutorial',
url: 'https://react-tutorial.meteor.com/simple-todos/01-creating-app.html',
});
await insertLink({
title: 'Follow the Guide',
url: 'https://guide.meteor.com',
});
await insertLink({
title: 'Read the Docs',
url: 'https://docs.meteor.com',
});
await insertLink({
title: 'Discussions',
url: 'https://forums.meteor.com',
});
}
});

View File

@@ -0,0 +1,20 @@
import assert from "assert";
describe("babel", function () {
it("package.json has correct name", async function () {
const { name } = await import("../package.json");
assert.strictEqual(name, "babel");
});
if (Meteor.isClient) {
it("client is not server", function () {
assert.strictEqual(Meteor.isServer, false);
});
}
if (Meteor.isServer) {
it("server is not client", function () {
assert.strictEqual(Meteor.isClient, false);
});
}
});

View File

@@ -0,0 +1,41 @@
import {
waitForMeteorOutput,
} from "./helpers";
import { testMeteorBundler, testMeteorRspackBundler } from './test-helpers';
describe('Babel App Bundling /', () => {
describe('Meteor Bundler /', testMeteorBundler({
appName: 'babel',
port: 3121
}));
describe('Meteor+Rspack Bundler /', testMeteorRspackBundler({
appName: 'babel',
port: 3122,
filePaths: {
client: 'client/main.jsx',
server: 'server/main.js',
test: 'tests/main.js'
},
customAssertions: {
afterRun: async ({ result }) => {
},
afterRunRebuildClient: async ({ allConsoleLogs }) => {
// Check for HMR output as enabled by default
await waitForMeteorOutput(allConsoleLogs, /.*HMR.*Updated modules:*/);
},
afterRunProduction: async ({ result }) => {
},
afterRunProductionRebuildClient: async ({ allConsoleLogs }) => {
// Check for HMR to not be enabled in production-like mode
await waitForMeteorOutput(allConsoleLogs, /.*HMR.*Updated modules:*/, { negate: true });
},
afterTest: async ({ result }) => {
},
afterTestOnce: async ({ result }) => {
},
afterBuild: async ({ result }) => {
},
}
}));
});