diff --git a/biome.json b/biome.json index 17a9d15..20b4762 100644 --- a/biome.json +++ b/biome.json @@ -6,10 +6,10 @@ "rules": { "recommended": true }, - "includes": ["**", "!**/dist", "!**/*.bs.js", "!**/lib"] + "includes": ["**", "!**/dist", "!**/*.bs.js", "!**/lib", "!**/__generated__"] }, "formatter": { "enabled": true, - "includes": ["**", "!**/dist", "!**/*.bs.js", "!**/lib"] + "includes": ["**", "!**/dist", "!**/*.bs.js", "!**/lib", "!**/__generated__"] } } diff --git a/bun.lockb b/bun.lockb index c0ffb41..b339a3c 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/mock-server/index.js b/mock-server/index.js new file mode 100644 index 0000000..2ca1c0c --- /dev/null +++ b/mock-server/index.js @@ -0,0 +1,94 @@ +import { createSchema, createYoga } from "graphql-yoga"; +import { createServer } from "node:http"; +import { readFileSync } from "node:fs"; +import { join, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const typeDefs = readFileSync(join(__dirname, "schema.graphql"), "utf-8"); + +const users = [ + { + id: "user-1", + name: "Alice Chen", + email: "alice@example.com", + avatarUrl: null, + }, + { + id: "user-2", + name: "Bob Martinez", + email: "bob@example.com", + avatarUrl: null, + }, +]; + +let posts = [ + { + id: "post-1", + title: "Getting Started with ReScript", + body: "ReScript is a robustly typed language that compiles to efficient and human-readable JavaScript. It comes with a lightning fast compiler toolchain that scales to any codebase size.", + createdAt: "2026-04-10T10:00:00Z", + authorId: "user-1", + }, + { + id: "post-2", + title: "Building with Rspack", + body: "Rspack is a high performance JavaScript bundler written in Rust. It offers strong compatibility with the webpack ecosystem while providing significantly better build performance.", + createdAt: "2026-04-11T14:30:00Z", + authorId: "user-2", + }, + { + id: "post-3", + title: "Emotion CSS-in-JS Patterns", + body: "Emotion is a performant and flexible CSS-in-JS library. It allows you to style applications with string or object styles and has a predictable composition model.", + createdAt: "2026-04-12T09:15:00Z", + authorId: "user-1", + }, +]; + +let nextPostId = 4; + +const resolvers = { + Query: { + posts: () => posts, + post: (_, { id }) => posts.find((p) => p.id === id) || null, + me: () => users[0], + }, + Mutation: { + createPost: (_, { title, body }) => { + const post = { + id: `post-${nextPostId++}`, + title, + body, + createdAt: new Date().toISOString(), + authorId: "user-1", + }; + posts.unshift(post); + return post; + }, + }, + Post: { + author: (post) => users.find((u) => u.id === post.authorId), + }, + Node: { + __resolveType: (obj) => { + if (obj.email) return "User"; + if (obj.title) return "Post"; + return null; + }, + }, +}; + +const yoga = createYoga({ + schema: createSchema({ typeDefs, resolvers }), + cors: { + origin: "http://localhost:8080", + credentials: true, + }, +}); + +const server = createServer(yoga); + +server.listen(4000, () => { + console.log("GraphQL server running at http://localhost:4000/graphql"); +}); diff --git a/mock-server/schema.graphql b/mock-server/schema.graphql new file mode 100644 index 0000000..2939c32 --- /dev/null +++ b/mock-server/schema.graphql @@ -0,0 +1,28 @@ +type Query { + posts: [Post!]! + post(id: ID!): Post + me: User +} + +type Mutation { + createPost(title: String!, body: String!): Post! +} + +type User implements Node { + id: ID! + name: String! + email: String! + avatarUrl: String +} + +type Post implements Node { + id: ID! + title: String! + body: String! + createdAt: String! + author: User! +} + +interface Node { + id: ID! +} diff --git a/package.json b/package.json index cea072a..d73cdd9 100644 --- a/package.json +++ b/package.json @@ -1,57 +1,68 @@ { - "name": "rspack-rescript-react", - "private": true, - "version": "1.0.0", - "scripts": { - "dev": "concurrently \"bun run res:dev\" \"rspack serve\"", - "build": "cross-env NODE_ENV=production rspack build", - "res:build": "rescript build", - "res:dev": "rescript watch", - "res:clean": "rescript clean", -"prepare": "husky", - "commit": "git-cz", - "format:check": "biome check .", - "format:write": "biome format . --write", - "lint:check": "biome lint .", - "lint": "biome lint --write .", - "test": "vitest run", - "test:watch": "vitest" - }, - "dependencies": { - "@emotion/css": "^11.13.5", - "@emotion/server": "^11.11.0", - "@rescript/core": "1.6.1", - "@rescript/react": "0.14.2", - "react": "^19.2.5", - "react-dom": "^19.2.5", - "rescript": "12.2.0" - }, - "devDependencies": { - "@biomejs/biome": "^2.4.11", - "@commitlint/cli": "^20.5.0", - "@commitlint/config-conventional": "^20.5.0", - "@commitlint/cz-commitlint": "^20.5.1", - "@rspack/cli": "1.7.11", - "@rspack/core": "^1.7.11", - "@rspack/plugin-react-refresh": "1.6.2", - "@svgr/webpack": "^8.1.0", - "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "^6.9.1", - "@testing-library/react": "^16.3.2", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "commitizen": "^4.3.1", - "concurrently": "^9.2.1", - "cross-env": "^10.1.0", - "husky": "^9.1.7", - "inquirer": "^13.4.1", - "jsdom": "^29.0.2", - "typescript": "^6.0.2", - "vitest": "^4.1.4" - }, - "config": { - "commitizen": { - "path": "@commitlint/cz-commitlint" - } - } + "name": "rspack-rescript-react", + "private": true, + "version": "1.0.0", + "scripts": { + "dev": "concurrently \"bun run res:dev\" \"rspack serve\" \"bun run dev:server\"", + "dev:server": "node mock-server/index.js", + "build": "cross-env NODE_ENV=production rspack build", + "relay": "rescript-relay-compiler", + "relay:watch": "rescript-relay-compiler --watch", + "res:build": "rescript build", + "res:dev": "rescript watch", + "res:clean": "rescript clean", + "prepare": "husky", + "commit": "git-cz", + "format:check": "biome check .", + "format:write": "biome format . --write", + "lint:check": "biome lint .", + "lint": "biome lint --write .", + "test": "vitest run", + "test:watch": "vitest" + }, + "dependencies": { + "@emotion/css": "^11.13.5", + "@emotion/server": "^11.11.0", + "@rescript/core": "1.6.1", + "@rescript/react": "0.14.2", + "react": "^19.2.5", + "react-dom": "^19.2.5", + "react-relay": "20.1.1", + "relay-runtime": "20.1.1", + "rescript": "12.2.0", + "rescript-relay": "4.4.1" + }, + "devDependencies": { + "@biomejs/biome": "^2.4.11", + "@commitlint/cli": "^20.5.0", + "@commitlint/config-conventional": "^20.5.0", + "@commitlint/cz-commitlint": "^20.5.1", + "@rspack/cli": "1.7.11", + "@rspack/core": "^1.7.11", + "@rspack/plugin-react-refresh": "1.6.2", + "@svgr/webpack": "^8.1.0", + "@testing-library/dom": "^10.4.1", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "commitizen": "^4.3.1", + "concurrently": "^9.2.1", + "cross-env": "^10.1.0", + "graphql": "16.11.0", + "graphql-yoga": "5.12.0", + "husky": "^9.1.7", + "inquirer": "^13.4.1", + "jsdom": "^29.0.2", + "typescript": "^6.0.2", + "vitest": "^4.1.4" + }, + "config": { + "commitizen": { + "path": "@commitlint/cz-commitlint" + } + }, + "trustedDependencies": [ + "rescript-relay" + ] } diff --git a/relay.config.js b/relay.config.js new file mode 100644 index 0000000..b232fb1 --- /dev/null +++ b/relay.config.js @@ -0,0 +1,6 @@ +module.exports = { + src: "./src", + schema: "./mock-server/schema.graphql", + artifactDirectory: "./src/__generated__", + language: "rescript", +}; diff --git a/rescript.json b/rescript.json index dea9f76..8bb2d9a 100644 --- a/rescript.json +++ b/rescript.json @@ -13,7 +13,8 @@ } ], "suffix": ".bs.js", - "dependencies": ["@rescript/core", "@rescript/react"], + "dependencies": ["@rescript/core", "@rescript/react", "rescript-relay"], + "ppx-flags": ["rescript-relay/ppx"], "jsx": { "version": 4, "mode": "automatic" diff --git a/rspack.config.js b/rspack.config.js index f39caee..9eaaea0 100644 --- a/rspack.config.js +++ b/rspack.config.js @@ -12,6 +12,9 @@ module.exports = { "process.env.NODE_ENV": JSON.stringify( isProduction ? "production" : "development", ), + "process.env.GRAPHQL_ENDPOINT": JSON.stringify( + process.env.GRAPHQL_ENDPOINT || "http://localhost:4000/graphql", + ), }), !isProduction && new ReactRefreshPlugin(), ].filter(Boolean), diff --git a/src/App.res b/src/App.res index 27f4431..0b5b344 100644 --- a/src/App.res +++ b/src/App.res @@ -60,22 +60,24 @@ Emotion.Css.injectGlobal(` module App = { @react.component let make = () => { -
+ {React.string("bun run dev:server")}
+
+