Skip to content

Commit

Permalink
Redesign server plugins (#1441)
Browse files Browse the repository at this point in the history
* Redesign server plugins

* Upgrade webpack server plugin

* Upgrade vite server plugin

* Update findCosmosPluginConfigs.test.ts

* Add Codecov badge

* Add dev server tests

* Update setup.ts

* Fix previous tests

* Fix dev server test

* Update mockConsole.ts

* Update devServer.ts

* Capture logs

* Make importModule for importing server plugins

* Add dev server plugin tests

* Fix mocking

* Make tests more resilient

* Rename helper

* Add test

* Remove retry stuff

* Remove unneeded .tsx extension

* Create test helper for mocking plugin configs

* Update devServerPlugin.ts

* Reorganize imports

* Fix test

* Rename test file

* Life mock files

* Add export test

* Test export plugin

* Implement config hook

* Implement config hook in exports

* Move server plugins

* Try to fix flaky test

* Update cypress.config.ts

* Find first available port

* Improve port retry plugin

* Update README.md

* Use config hook in Vite plugin

* Simplify file names

* Use unique port in export tests

* Update getUserWebpackConfig.ts

* Separate importModule from importJson and get rid of deprecated boilerplate

* Test change

* Revert change

* Test override example

* Refactor FS module

* Update webpack override example

* Remove console.logs

* Test message handler API

* Test exporting UI plugins

* Update exportUiPlugin.ts

* Fix UI path on Windows

* Clean up playground bundle mocks

* Test plugin endpoint

* Remove ambiguity

* Fix UI path

* Fix Window path

* Fix Windows path

* Fix Windows paths

* Update devServerUiPlugin.ts

* Update devServerUiPlugin.ts

* Prettify and add code explanation

* Fix explanation
  • Loading branch information
ovidiuch committed Apr 10, 2023
1 parent f81ed4d commit 0d1dbd5
Show file tree
Hide file tree
Showing 67 changed files with 1,319 additions and 361 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ npm-debug.log
yarn-error.log

packages/*/dist
__testFs__

coverage
cypress/screenshots
Expand Down
13 changes: 12 additions & 1 deletion .jest/config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,28 @@ module.exports = {
testMatch: ['**/__tests__/**/*.{ts,tsx}', '**/?(*.)test.{ts,tsx}'],
testPathIgnorePatterns: ['<rootDir>/node_modules/'],
setupFilesAfterEnv: ['<rootDir>/.jest/setup.ts'],
modulePathIgnorePatterns: ['__testFs__'],
moduleNameMapper: {
// This seems faster than transpiling node_modules/lodash-es
'lodash-es': '<rootDir>/node_modules/lodash/lodash.js',
// Jest with jsdom environment imports the "browser" ws export, which
// is a noop because wp isn't meant to be used in a browser environment.
// Issue introduced here https://github.com/websockets/ws/pull/2118
ws: '<rootDir>/node_modules/ws/index.js',
// These files are mocked because they are only available after
// Cosmos packages are built, and tests should run with source code only.
'react-cosmos-ui/dist/playground.bundle.js.map':
'<rootDir>/packages/react-cosmos/src/server/testMocks/playground.bundle.js.map',
'react-cosmos-ui/dist/playground.bundle.js':
'<rootDir>/packages/react-cosmos/src/server/testMocks/playground.bundle.js',
},
// https://kulshekhar.github.io/ts-jest/docs/getting-started/options/tsconfig
transform: {
'^.+\\.tsx?$': ['ts-jest', { tsconfig: { noUnusedLocals: false } }],
'^.+\\.js$': ['ts-jest', { tsconfig: { allowJs: true } }],
'^.+\\.js$': [
'ts-jest',
{ tsconfig: { allowJs: true, noUnusedLocals: false } },
],
},
// https://jestjs.io/docs/configuration#transformignorepatterns-arraystring
transformIgnorePatterns: [
Expand All @@ -45,6 +55,7 @@ module.exports = {
'!**/*.fixture.{js,ts,tsx}',
'!**/cosmos.decorator.{js,ts,tsx}',
'!**/testHelpers/**',
'!**/testMocks/**',
'!**/@types/**',
// Ignore coverage from dark launched plugins
'!packages/react-cosmos-ui/src/plugins/PluginList/**',
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

> 🚀 **React Cosmos 6 is here! Check out the [migration guide](docs/MIGRATION_V6.md) to get started.**
[![npm version](https://img.shields.io/npm/v/react-cosmos.svg?style=flat)](https://www.npmjs.com/package/react-cosmos) [![CI Status](https://github.com/react-cosmos/react-cosmos/actions/workflows/test.yml/badge.svg)](https://github.com/react-cosmos/react-cosmos/actions/workflows/test.yml) [![Twitter](https://img.shields.io/badge/twitter-follow-%2300acee)](https://twitter.com/ReactCosmos) [![Discord](https://img.shields.io/discord/620737684859781150?color=%236D74EF)](https://discord.gg/3X95VgfnW5) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/react-cosmos/react-cosmos/blob/main/CONTRIBUTING.md#how-to-contribute)
[![npm version](https://img.shields.io/npm/v/react-cosmos.svg?style=flat)](https://www.npmjs.com/package/react-cosmos) [![CI Status](https://github.com/react-cosmos/react-cosmos/actions/workflows/test.yml/badge.svg)](https://github.com/react-cosmos/react-cosmos/actions/workflows/test.yml) ![Codecov](https://img.shields.io/codecov/c/github/react-cosmos/react-cosmos) [![Twitter](https://img.shields.io/badge/twitter-follow-%2300acee)](https://twitter.com/ReactCosmos) [![Discord](https://img.shields.io/discord/620737684859781150?color=%236D74EF)](https://discord.gg/3X95VgfnW5) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/react-cosmos/react-cosmos/blob/main/CONTRIBUTING.md#how-to-contribute)

Sandbox for developing and testing UI components in isolation.

Expand Down
5 changes: 5 additions & 0 deletions cypress/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,10 @@ export default defineConfig({
modifyObstructiveCode: false,
e2e: {
specPattern: 'cypress/tests/**/*.{js,jsx,ts,tsx}',
// Disabled test isoation to try to fix flakiness of domDev test on Windows.
// Every now and then it would fail before running any test with the message:
// "This page was cleared by navigating to about:blank."
// Found it here: https://stackoverflow.com/a/74762655
testIsolation: false,
},
});
3 changes: 2 additions & 1 deletion docs/roadmap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
- [x] Extract react-cosmos-plugin-open-fixture plugin package.
- [x] Move Boolean input plugin from example to plugin package.
- [x] Add support for server plugins.
- [x] Test plugin APIs.
- [ ] Document plugin APIs.
- [ ] Add guide for creating UI + server plugin.

## Quality of life

- [ ] Change default port because [port 5000 is taken on macOS 12](https://github.com/react-cosmos/react-cosmos/issues/1355).
- [x] Auto port retry because [port 5000 is taken on macOS 12](https://github.com/react-cosmos/react-cosmos/issues/1355).
- [x] Fix issues with Yarn 2 and PnP [#946](https://github.com/react-cosmos/react-cosmos/issues/946) [#1266](https://github.com/react-cosmos/react-cosmos/issues/1266) [#1337](https://github.com/react-cosmos/react-cosmos/pull/1337) [#1386](https://github.com/react-cosmos/react-cosmos/issues/1386).
- [x] Fix security issues.
- [x] Drop IE support.
Expand Down
3 changes: 1 addition & 2 deletions examples/vite/cosmos.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@
"react-cosmos-plugin-boolean-input",
"react-cosmos-plugin-open-fixture",
"react-cosmos-plugin-vite"
],
"rendererUrl": "http://localhost:5050"
]
}
3 changes: 3 additions & 0 deletions examples/webpack/cosmos.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"$schema": "../../packages/react-cosmos/config.schema.json",
"globalImports": ["src/global.css"],
"staticPath": "static",
"webpack": {
"overridePath": "webpack.override.js"
},
"plugins": [
"react-cosmos-plugin-boolean-input",
"react-cosmos-plugin-open-fixture",
Expand Down
4 changes: 4 additions & 0 deletions examples/webpack/webpack.override.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default function (webpackConfig, env) {
// Customize webpack config for Cosmos...
return webpackConfig;
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@types/express": "4.17.17",
"@types/fuzzaldrin-plus": "^0.6.2",
"@types/glob": "^8.0.1",
"@types/isomorphic-fetch": "^0.0.36",
"@types/jest": "^29.4.0",
"@types/lodash-es": "^4.17.6",
"@types/micromatch": "^4.0.2",
Expand Down Expand Up @@ -66,6 +67,7 @@
"glob": "^8.1.0",
"html-webpack-plugin": "^5.5.0",
"http-server": "^14.1.1",
"isomorphic-fetch": "^3.0.0",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
"jest-styled-components": "^7.1.1",
Expand Down
6 changes: 2 additions & 4 deletions packages/react-cosmos-core/src/server/cosmosPluginConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
export type RawCosmosPluginConfig = {
name: string;
ui?: string;
devServer?: string;
export?: string;
server?: string;
};

export type CosmosPluginConfig = {
name: string;
rootDir: string;
ui?: string;
devServer?: string;
export?: string;
server?: string;
};

export type UiCosmosPluginConfig = CosmosPluginConfig & {
Expand Down
3 changes: 1 addition & 2 deletions packages/react-cosmos-plugin-vite/cosmos.plugin.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"name": "Vite",
"devServer": "dist/viteDevServerPlugin.js",
"export": "dist/viteExportPlugin.js"
"server": "dist/viteServerPlugin.js"
}
17 changes: 17 additions & 0 deletions packages/react-cosmos-plugin-vite/src/createViteCosmosConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { CosmosConfig } from 'react-cosmos/server.js';

type ViteCosmosConfig = {
port: number;
};

type ViteCosmosConfigInput = Partial<ViteCosmosConfig>;

export function createViteCosmosConfig(
cosmosConfig: CosmosConfig
): ViteCosmosConfig {
const configInput: ViteCosmosConfigInput = cosmosConfig.vite || {};

return {
port: configInput.port || 5050,
};
}
30 changes: 30 additions & 0 deletions packages/react-cosmos-plugin-vite/src/viteConfigPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {
CosmosConfig,
CosmosConfigPluginArgs,
findNextAvailablePort,
} from 'react-cosmos/server.js';
import { createViteCosmosConfig } from './createViteCosmosConfig.js';

export async function viteConfigPlugin({
cosmosConfig,
}: CosmosConfigPluginArgs): Promise<CosmosConfig> {
const { rendererUrl } = cosmosConfig;
if (rendererUrl) {
return cosmosConfig;
}

const viteCosmosConfig = createViteCosmosConfig(cosmosConfig);
const port = await findNextAvailablePort(
viteCosmosConfig.port,
cosmosConfig.portRetries
);

return {
...cosmosConfig,
rendererUrl: `http://localhost:${port}`,
vite: {
...viteCosmosConfig,
port: port,
},
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
userDepsResolvedModuleId,
} from './reactCosmosViteRollupPlugin.js';

export default async function viteDevServerPlugin({
export async function viteDevServerPlugin({
platformType,
cosmosConfig,
}: DevServerPluginArgs) {
Expand Down
4 changes: 1 addition & 3 deletions packages/react-cosmos-plugin-vite/src/viteExportPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import { ExportPluginArgs, RENDERER_FILENAME } from 'react-cosmos/server.js';
import { build } from 'vite';
import { reactCosmosViteRollupPlugin } from './reactCosmosViteRollupPlugin.js';

export default async function viteExportPlugin({
cosmosConfig,
}: ExportPluginArgs) {
export async function viteExportPlugin({ cosmosConfig }: ExportPluginArgs) {
const { exportPath, publicUrl } = cosmosConfig;

await build({
Expand Down
13 changes: 13 additions & 0 deletions packages/react-cosmos-plugin-vite/src/viteServerPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { CosmosServerPlugin } from 'react-cosmos/server.js';
import { viteConfigPlugin } from './viteConfigPlugin.js';
import { viteDevServerPlugin } from './viteDevServerPlugin.js';
import { viteExportPlugin } from './viteExportPlugin.js';

const viteServerPlugin: CosmosServerPlugin = {
name: 'vite',
config: viteConfigPlugin,
devServer: viteDevServerPlugin,
export: viteExportPlugin,
};

export default viteServerPlugin;
3 changes: 1 addition & 2 deletions packages/react-cosmos-plugin-webpack/cosmos.plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"name": "Webpack",
"ui": "dist/ui/build.js",
"devServer": "dist/server/webpackDevServerPlugin.js",
"export": "dist/server/webpackExportPlugin.js"
"server": "dist/server/webpackServerPlugin.js"
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function createWebpackCosmosConfig(
cosmosConfig: CosmosConfig
): WebpackCosmosConfig {
const { rootDir } = cosmosConfig;
const configInput = (cosmosConfig.webpack || {}) as WebpackCosmosConfigInput;
const configInput: WebpackCosmosConfigInput = cosmosConfig.webpack || {};

return {
configPath: getWebpackConfigPath(configInput, rootDir),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import {
mockCliArgs,
mockConsole,
mockFile,
mockCwdModuleDefault,
unmockCliArgs,
} from 'react-cosmos/jest.js';
import '../../testHelpers/mockEsmClientPath.js';
Expand All @@ -28,8 +28,8 @@ const mockWebpackOverride = jest.fn((webpackConfig: webpack.Configuration) => ({
beforeAll(() => {
mockWebpackConfig.mockClear();
mockCliArgs({ env: { prod: true }, fooEnvVar: true });
mockFile('mywebpack.config.js', mockWebpackConfig);
mockFile('mywebpack.override.js', mockWebpackOverride);
mockCwdModuleDefault('mywebpack.config.js', mockWebpackConfig);
mockCwdModuleDefault('mywebpack.override.js', mockWebpackOverride);
});

afterAll(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
// NOTE: Mock files need to imported before modules that use the mocked APIs
import { mockConsole, mockFile, unmockCliArgs } from 'react-cosmos/jest.js';
import {
mockConsole,
mockCwdModuleDefault,
unmockCliArgs,
} from 'react-cosmos/jest.js';
import '../../testHelpers/mockEsmClientPath.js';
import '../../testHelpers/mockEsmLoaderPath.js';
import '../../testHelpers/mockEsmRequire.js';
Expand All @@ -15,7 +19,7 @@ import { getExportWebpackConfig } from '../getExportWebpackConfig.js';
import { HtmlWebpackPlugin } from '../htmlPlugin.js';

beforeAll(() => {
mockFile('mywebpack.config.js', {
mockCwdModuleDefault('mywebpack.config.js', {
module: { rules: [MY_RULE] },
plugins: [MY_PLUGIN],
});
Expand All @@ -31,7 +35,9 @@ const MY_PLUGIN = {};
async function getCustomExportWebpackConfig() {
return mockConsole(async ({ expectLog }) => {
expectLog('[Cosmos] Using webpack config found at mywebpack.config.js');
expectLog('[Cosmos] Learn how to override webpack config for cosmos: https://github.com/react-cosmos/react-cosmos/tree/main/docs#webpack-config-override');
expectLog(
'[Cosmos] Learn how to override webpack config for cosmos: https://github.com/react-cosmos/react-cosmos/tree/main/docs#webpack-config-override'
);
const cosmosConfig = createCosmosConfig(process.cwd(), {
webpack: {
configPath: 'mywebpack.config.js',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// NOTE: Mock files need to imported before modules that use the mocked APIs
import { mockConsole, mockFile } from 'react-cosmos/jest.js';
import { mockConsole, mockCwdModuleDefault } from 'react-cosmos/jest.js';
import '../../testHelpers/mockEsmClientPath.js';
import '../../testHelpers/mockEsmLoaderPath.js';
import '../../testHelpers/mockEsmRequire.js';
Expand All @@ -12,6 +12,9 @@ import { getDevWebpackConfig } from '../getDevWebpackConfig.js';
async function getCustomDevWebpackConfig() {
return mockConsole(async ({ expectLog }) => {
expectLog('[Cosmos] Using webpack config found at mywebpack.config.js');
expectLog(
'[Cosmos] Learn how to override webpack config for cosmos: https://github.com/react-cosmos/react-cosmos/tree/main/docs#webpack-config-override'
);
const cosmosConfig = createCosmosConfig(process.cwd(), {
webpack: {
configPath: 'mywebpack.config.js',
Expand All @@ -26,7 +29,7 @@ class BarResolvePlugin {}
class ModuleScopePlugin {}

it('removes ModuleScopePlugin resolve plugin', async () => {
mockFile('mywebpack.config.js', () => ({
mockCwdModuleDefault('mywebpack.config.js', () => ({
resolve: {
plugins: [new ModuleScopePlugin()],
},
Expand All @@ -37,7 +40,7 @@ it('removes ModuleScopePlugin resolve plugin', async () => {
});

it('keeps other resolve plugins', async () => {
mockFile('mywebpack.config.js', () => ({
mockCwdModuleDefault('mywebpack.config.js', () => ({
resolve: {
plugins: [
new ModuleScopePlugin(),
Expand Down

0 comments on commit 0d1dbd5

Please sign in to comment.