Skip to content

Commit

Permalink
feat(workspace-tools): Added the node-library generator
Browse files Browse the repository at this point in the history
  • Loading branch information
sullivanpj committed Nov 7, 2023
1 parent cdceef8 commit 85ada65
Show file tree
Hide file tree
Showing 23 changed files with 468 additions and 26 deletions.
9 changes: 7 additions & 2 deletions packages/linting-tools/src/tsconfig/tsconfig.root.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": false,
"noFallthroughCasesInSwitch": true,
"allowImportingTsExtensions": true,
"importHelpers": true,
"target": "es2022",
"target": "esnext",
"module": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"lib": ["esnext", "dom", "dom.iterable"],
"skipLibCheck": true,
"skipDefaultLibCheck": true
},
Expand Down
3 changes: 2 additions & 1 deletion packages/testing-tools/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./jest/config";
export * from "./jest/package.config";
export * from "./jest/workspace.config";
34 changes: 34 additions & 0 deletions packages/testing-tools/src/jest/package.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { join } from "path";

/**
* Config for Jest unit tests
*
* https://jestjs.io/docs/configuration#projects-arraystring--projectconfig
*/

/**
* Config for Jest unit tests
*
* @remarks Please see [the Jest documentation](https://jestjs.io/docs/configuration#projects-arraystring--projectconfig) for more information.
*
* @param projectDir The directory of the project
* @param isNode Whether the project is a Node project
* @param displayName The name to display in the Jest output
* @returns The Jest configuration
*/
export const getJestConfig = (
projectDir: string,
isNode = true,
displayName?: string
) => ({
displayName: displayName
? displayName
: projectDir.replaceAll("\\", "-").replaceAll("/", "-"),
preset: "@storm-software/testing-tools/jest/preset.js",
testEnvironment: isNode ? "node" : "jsdom",
transform: {
"^.+\\.[tj]s$": ["ts-jest", { tsconfig: "<rootDir>/tsconfig.spec.json" }]
},
moduleFileExtensions: ["ts", "js", "html"],
coverageDirectory: join("../../coverage", projectDir)
});
File renamed without changes.
8 changes: 4 additions & 4 deletions packages/workspace-tools/executors.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"executors": {
"build": {
"implementation": "./executors/build/executor",
"schema": "./executors/build/schema.json",
"tsup": {
"implementation": "./executors/tsup/executor",
"schema": "./executors/tsup/schema.json",
"description": "Run a build on the project using tsup configuration",
"hasher": "./executors/build/hasher"
"hasher": "./executors/tsup/hasher"
}
}
}
7 changes: 7 additions & 0 deletions packages/workspace-tools/generators.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
"schema": "./src/generators/preset/schema.json",
"description": "Storm workspace preset generator",
"x-use-standalone-layout": true
},
"node-library": {
"factory": "./src/generators/node-library/generator",
"schema": "./src/generators/node-library/schema.json",
"aliases": ["node-lib"],
"x-type": "library",
"description": "Generate a new node library project in the Storm workspace"
}
}
}
2 changes: 2 additions & 0 deletions packages/workspace-tools/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from "./src/executors/tsup/executor";
export * from "./src/generators/init/init";
export * from "./src/generators/node-library/generator";
export * from "./src/generators/preset/generator";
export * from "./src/utils/versions";
10 changes: 0 additions & 10 deletions packages/workspace-tools/src/executors/tsup/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,6 @@ export default async function runExecutor(
input: "LICENSE",
output: "."
});
assets.push({
glob: "",
input: "assets/logo-light.png",
output: "."
});
assets.push({
glob: "",
input: "assets/logo-dark.png",
output: "."
});

const result = await copyAssets(
{ assets, watch: options.watch, outputPath },
Expand Down
2 changes: 1 addition & 1 deletion packages/workspace-tools/src/executors/tsup/schema.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "http://json-schema.org/schema",
"version": 2,
"title": "Build executor",
"title": "Tsup Build executor",
"description": "",
"type": "object",
"properties": {
Expand Down
5 changes: 4 additions & 1 deletion packages/workspace-tools/src/generators/init/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ export async function stormInitGenerator(tree: Tree, schema: Schema) {
tree,
{
"nx": nxVersion,
"@nx/workspace": nxVersion
"@nx/workspace": nxVersion,
"@storm-software/testing-tools": "latest",
"@storm-software/git-tools": "latest",
"@storm-software/linting-tools": "latest"
},
{}
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!-- START header -->
<!-- END header -->

# <%= name %>

<!-- START doctoc -->
<!-- END doctoc -->

## Reduced Package Size

This project uses [tsup](https://tsup.egoist.dev/) to package the source code due to its ability to remove unused code and ship smaller javascript files thanks to code splitting. This helps to greatly reduce the size of the package and to make it easier to use in other projects.

## Development

This project is built using [Nx](https://nx.dev). As a result, many of the usual commands are available to assist in development.

### Building

Run `nx build <%= name %>` to build the library.

### Running unit tests

Run `nx test <%= name %>` to execute the unit tests via [Jest](https://jestjs.io).

### Linting

Run `nx lint <%= name %>` to run [ESLint](https://eslint.org/) on the package.

<!-- START footer -->
<!-- END footer -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { getJestConfig } from "@storm-software/testing-tools";

export default getJestConfig("<%= projectDir %>", true, "<%= name %>");
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const variable = "<%= name %>";
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "<%= offsetFromRoot %>/dist/out-tsc",
"types": ["jest", "node"]
},
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Tree, readProjectConfiguration } from "@nx/devkit";
import { createTreeWithEmptyWorkspace } from "@nx/devkit/testing";

import { nodeLibraryGenerator } from "./generator";
import { NodeLibraryGeneratorSchema } from "./schema";

describe("node-library generator", () => {
let tree: Tree;
const options: NodeLibraryGeneratorSchema = { name: "test" };

beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});

it("should run successfully", async () => {
await nodeLibraryGenerator(tree, options);
const config = readProjectConfiguration(tree, "test");
expect(config).toBeDefined();
});
});
176 changes: 176 additions & 0 deletions packages/workspace-tools/src/generators/node-library/generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import {
GeneratorCallback,
Tree,
addDependenciesToPackageJson,
addProjectConfiguration,
formatFiles,
generateFiles,
joinPathFragments,
names,
offsetFromRoot,
updateJson,
writeJson
} from "@nx/devkit";
import { getRelativePathToRootTsConfig, tsConfigBaseOptions } from "@nx/js";
import jsInitGenerator from "@nx/js/src/generators/init/init";
import { NormalizedSchema } from "@nx/js/src/generators/library/library";
import setupVerdaccio from "@nx/js/src/generators/setup-verdaccio/generator";
import { PackageJson } from "nx/src/utils/package-json";
import { join } from "path";
import { typesNodeVersion } from "../../utils/versions";
import { normalizeOptions } from "./normalize-options";
import { NodeLibraryGeneratorSchema } from "./schema";

export async function nodeLibraryGenerator(
tree: Tree,
schema: NodeLibraryGeneratorSchema
) {
const filesDir = join(__dirname, "./files");
const options = await normalizeOptions(tree, schema);

const tasks: GeneratorCallback[] = [];
tasks.push(
await jsInitGenerator(tree, {
...options,
tsConfigName: options.rootProject ? "tsconfig.json" : "tsconfig.base.json"
})
);

tasks.push(
addDependenciesToPackageJson(
tree,
{},
{
"@storm-software/workspace-tools": "latest",
"@storm-software/testing-tools": "latest",
"@types/node": typesNodeVersion
}
)
);

if (options.publishable) {
tasks.push(await setupVerdaccio(tree, { ...options, skipFormat: true }));
}

const { className, name, propertyName } = names(
options.projectNames.projectFileName
);

createProjectTsConfigJson(tree, options);

addProjectConfiguration(tree, options.name, {
root: options.directory,
projectType: "library",
sourceRoot: `${options.directory}/src`,
targets: {
build: {
executor: "@storm-software/workspace-tools:tsup",
outputs: ["{options.outputPath}"],
options: {
outputPath: getOutputPath(options),
main: join(options.projectRoot, "src/index.ts"),
tsConfig: join(options.projectRoot, "tsconfig.json"),
project: join(options.projectRoot, "package.json")
}
},
lint: {},
test: {}
}
});

generateFiles(tree, filesDir, options.projectRoot, {
...options,
dot: ".",
className,
name,
propertyName,
js: !!options.js,
cliCommand: "nx",
strict: undefined,
tmpl: "",
offsetFromRoot: offsetFromRoot(options.projectRoot),
buildable: options.bundler && options.bundler !== "none",
hasUnitTestRunner: options.unitTestRunner !== "none"
});

const packageJsonPath = joinPathFragments(
options.projectRoot,
"package.json"
);

updateJson<PackageJson>(tree, packageJsonPath, (json: PackageJson) => {
json.name = options.importPath;
json.version = "0.0.1";
// If the package is publishable or root/standalone, we should remove the private field.
if (json.private && (options.publishable || options.rootProject)) {
delete json.private;
}
return {
...json,
files: ["build", "src"],
type: "module",
types: "legacy/index.d.ts",
main: "legacy/index.cjs",
module: "legacy/index.js",
exports: {
".": {
import: {
types: "./modern/index.d.ts",
default: "./modern/index.js"
},
require: {
types: "./modern/index.d.cts",
default: "./modern/index.cjs"
}
},
"./package.json": "./package.json"
},
sideEffects: false,
dependencies: {
...json.dependencies
},
publishConfig: {
access: "public"
}
} as unknown as PackageJson;
});

await formatFiles(tree);
}

function getOutputPath(options: NormalizedSchema) {
const parts = ["dist"];
if (options.projectRoot === ".") {
parts.push(options.name);
} else {
parts.push(options.projectRoot);
}
return joinPathFragments(...parts);
}

function createProjectTsConfigJson(tree: Tree, options: NormalizedSchema) {
const tsconfig = {
extends: options.rootProject
? undefined
: getRelativePathToRootTsConfig(tree, options.projectRoot),
compilerOptions: {
...(options.rootProject ? tsConfigBaseOptions : {}),
outDir: joinPathFragments(
offsetFromRoot(options.projectRoot),
"dist/out-tsc"
),
noEmit: true
},
files: [],
include: ["src/**/*.ts", "src/**/*.js", "bin/**/*"],
exclude: ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
};

writeJson(
tree,
joinPathFragments(options.projectRoot, "tsconfig.json"),
tsconfig
);
}

export default nodeLibraryGenerator;
Loading

0 comments on commit 85ada65

Please sign in to comment.