forked from plasmicapp/plasmic
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* build.mjs for consistent builds + package.json validation * Common TypeScript config * Common ESLint config for TypeScript and React * Common Prettier config * Common Jest config * Fix pre-commit setup to actually run eslint Change-Id: If14ce54ffa6e7ec64413096611a8a033ab60a033
- Loading branch information
Showing
10 changed files
with
2,525 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/** ESLint config for packages NOT using frameworks like React. */ | ||
module.exports = { | ||
extends: [ | ||
'eslint:recommended', | ||
'plugin:@typescript-eslint/recommended', | ||
'plugin:prettier/recommended', | ||
], | ||
parser: '@typescript-eslint/parser', | ||
plugins: ['@typescript-eslint'], | ||
root: true, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/** ESLint config for packages using React. */ | ||
module.exports = { | ||
extends: ['./.eslintrc.js', 'react-app'], | ||
settings: { | ||
react: { | ||
version: 'detect', | ||
}, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,29 @@ | ||
repos: | ||
- repo: https://github.com/pre-commit/mirrors-prettier | ||
rev: v2.3.1 | ||
hooks: | ||
- id: prettier | ||
files: ^.*\.(js|jsx|ts|tsx|json|css|scss|md|toml|xml)$ | ||
exclude: (^.*/plasmic/.*$|.md$) | ||
additional_dependencies: | ||
- [email protected] | ||
- prettier-plugin-organize-imports | ||
- typescript | ||
- repo: https://github.com/pre-commit/mirrors-prettier | ||
rev: v2.2.0 | ||
hooks: | ||
- id: prettier | ||
files: ^.*/plasmic/.*\.(js|jsx|ts|tsx|json|css|scss|md|toml|xml)$ | ||
- repo: https://github.com/pre-commit/pre-commit-hooks | ||
rev: v2.3.0 | ||
rev: v4.4.0 | ||
hooks: | ||
- id: check-merge-conflict | ||
- id: trailing-whitespace | ||
exclude: ^.*/__snapshots__/.*$ | ||
- repo: https://github.com/pre-commit/mirrors-eslint | ||
rev: v7.20.0 | ||
rev: v8.38.0 | ||
hooks: | ||
- id: eslint | ||
files: ^wab/src/.*\.(ts|tsx)$ | ||
types: [file] | ||
files: ^.*\.(ts|tsx)$ | ||
exclude: ^.*/plasmic/.*$ | ||
additional_dependencies: | ||
- "@typescript-eslint/[email protected]" | ||
- "@typescript-eslint/[email protected]" | ||
- "[email protected]" | ||
- "[email protected]" | ||
- "[email protected]" | ||
- "[email protected]" | ||
- repo: https://github.com/pre-commit/mirrors-prettier | ||
rev: v2.7.1 | ||
hooks: | ||
- id: prettier | ||
types: [file] | ||
files: ^.*\.(js|jsx|ts|tsx|json|css|scss|toml|xml)$ | ||
exclude: ^.*/plasmic/.*$ | ||
additional_dependencies: | ||
- eslint | ||
- "@typescript-eslint/eslint-plugin" | ||
- "@typescript-eslint/parser" | ||
- [email protected] | ||
- [email protected] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
{ | ||
"trailingComma": "es5", | ||
"semi": true | ||
"printWidth": 80, | ||
"semi": true, | ||
"singleQuote": true, | ||
"trailingComma": "es5" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
/** | ||
* Validates package.json and builds bundles in a consistently across our packages. | ||
*/ | ||
|
||
import fs from 'fs/promises'; | ||
import console from 'console'; | ||
import path from 'path'; | ||
import process from 'process'; | ||
import esbuild from 'esbuild'; | ||
|
||
async function main() { | ||
if (process.argv.length < 3) { | ||
throw new Error('missing entry point'); | ||
} | ||
|
||
const entryPoint = process.argv[2]; | ||
const options = process.argv.slice(3); | ||
|
||
const useClient = findAndRemoveOption(options, '--use-client'); | ||
// By default, we only ship cjs bundles. Use this option to also ship esm bundles. | ||
// However, there are many issues that need to be resolved before turning this option on. | ||
// https://app.shortcut.com/plasmic/story/33688/es-module-support | ||
const esm = findAndRemoveOption(options, '--esm-do-not-use'); | ||
const watch = findAndRemoveOption(options, '--watch'); | ||
if (options.length > 0) { | ||
throw new Error(`unknown or duplicate options: ${options.join(' ')}`); | ||
} | ||
|
||
const name = path.parse(entryPoint).name; | ||
|
||
const expectedPackageJson = generateExpectedPackageJson(name, esm); | ||
const actualPackageJson = JSON.parse( | ||
await fs.readFile(path.resolve('package.json')) | ||
); | ||
validatePackageJson(actualPackageJson, expectedPackageJson); | ||
|
||
const ctx = { | ||
entryPoint, | ||
name, | ||
formats: esm ? ['cjs', 'esm'] : ['cjs'], | ||
useClient, | ||
watch, | ||
}; | ||
|
||
await buildBundle(ctx); | ||
} | ||
|
||
function findAndRemoveOption(options, option) { | ||
const index = options.indexOf(option); | ||
const found = index >= 0; | ||
if (found) { | ||
options.splice(index, 1); | ||
} | ||
return found; | ||
} | ||
|
||
function generateExpectedPackageJson(name, esm) { | ||
const subpath = name === 'index' ? '.' : `./${name}`; | ||
const packageJson = { | ||
exports: { | ||
[subpath]: generateExpectedPackageJsonSubpath(name, esm), | ||
}, | ||
}; | ||
|
||
if (name === 'index') { | ||
packageJson.types = './dist/index.d.ts'; | ||
packageJson.main = './dist/index.js'; | ||
if (esm) { | ||
// "index.esm.js" should be set as the "module" field for webpack 4 and other tools, | ||
// since they don't support the "exports" field. | ||
// We change the extension from ".mjs" to ".js" because ".mjs" doesn't work properly in webpack 4. | ||
// https://github.com/adobe/react-spectrum/pull/4038 | ||
packageJson.module = './dist/index.esm.js'; | ||
} | ||
} else if (name === 'react-server') { | ||
packageJson.exports['./react-server-conditional'] = { | ||
'react-server': generateExpectedPackageJsonSubpath('react-server', esm), | ||
default: generateExpectedPackageJsonSubpath('index', esm), | ||
}; | ||
} | ||
|
||
return packageJson; | ||
} | ||
|
||
function generateExpectedPackageJsonSubpath(name, esm) { | ||
if (esm) { | ||
return { | ||
types: `./dist/${name}.d.ts`, | ||
import: `./dist/${name}.mjs`, | ||
require: `./dist/${name}.js`, | ||
}; | ||
} else { | ||
return { | ||
types: `./dist/${name}.d.ts`, | ||
default: `./dist/${name}.js`, | ||
}; | ||
} | ||
} | ||
|
||
/** Validates that `expected` is a subset of `actual`. Throws if not. */ | ||
function validatePackageJson(actual, expected, path = '') { | ||
for (const [key, expectedValue] of Object.entries(expected)) { | ||
const nestedPath = path ? `${path} > "${key}"` : `"${key}"`; | ||
if (!(key in actual)) { | ||
throw new Error(`package.json ${nestedPath} field missing`); | ||
} | ||
|
||
if (typeof expectedValue === 'string') { | ||
if (expectedValue !== actual[key]) { | ||
throw new Error( | ||
`package.json ${nestedPath} field should be "${expectedValue}"` | ||
); | ||
} | ||
} else { | ||
validatePackageJson(actual[key], expectedValue, nestedPath); | ||
} | ||
} | ||
} | ||
|
||
async function buildBundle({ entryPoint, name, formats, useClient, watch }) { | ||
return Promise.all( | ||
formats.map(async (format) => { | ||
const outfile = `dist/${name}.${format === 'cjs' ? 'js' : 'mjs'}`; | ||
const esbuildOptions = { | ||
bundle: true, | ||
packages: 'external', // don't bundle node_modules | ||
|
||
entryPoints: [entryPoint], | ||
format, | ||
target: 'es6', | ||
outfile, | ||
|
||
banner: { | ||
js: useClient ? `"use client";` : ``, | ||
}, | ||
|
||
sourcemap: true, | ||
}; | ||
if (watch) { | ||
await (await esbuild.context(esbuildOptions)).watch(); | ||
console.info( | ||
`watching and rebuilding ${format.toUpperCase()} bundle at "${outfile}"...` | ||
); | ||
} else { | ||
await esbuild.build(esbuildOptions); | ||
console.info(`built ${format.toUpperCase()} bundle at "${outfile}"`); | ||
|
||
// Copy "index.mjs" to "index.esm.js". | ||
// "index.esm.js" should be set as the "module" field for webpack 4 and other tools, | ||
// since they don't support the "exports" field. | ||
// We change the extension from ".mjs" to ".js" because ".mjs" doesn't work properly in webpack 4. | ||
// https://github.com/adobe/react-spectrum/pull/4038 | ||
if (outfile === 'dist/index.mjs') { | ||
await fs.copyFile('dist/index.mjs', 'dist/index.esm.js'); | ||
console.info( | ||
`built ${format.toUpperCase()} bundle at "dist/index.esm.js"` | ||
); | ||
} | ||
} | ||
}) | ||
); | ||
} | ||
|
||
try { | ||
await main(); | ||
} catch (error) { | ||
console.error(error); | ||
process.exit(1); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
const esbuild = require('esbuild'); | ||
|
||
// This transforms TypeScript to JavaScript for Jest. | ||
// We use esbuild here for speed and consistency with our actual builds. | ||
// https://jestjs.io/docs/code-transformation | ||
module.exports = { | ||
process: (sourceText, sourcePath, _options) => { | ||
const { code, map } = esbuild.transformSync(sourceText, { | ||
format: 'cjs', | ||
loader: 'ts', | ||
sourcefile: sourcePath, | ||
sourcemap: 'both', | ||
target: `node${process.versions.node}`, | ||
}); | ||
return { code, map }; | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = { | ||
testRegex: '.(spec|test).(js|jsx|ts|tsx)$', | ||
transform: { | ||
'\\.tsx?$': '<rootDir>/jest-transform-esbuild.js', | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
{ | ||
// Common tsconfig used for type checking and generating declaration files. | ||
// Docs: https://www.typescriptlang.org/tsconfig | ||
"exclude": [ | ||
"**/__specs__/**", | ||
"**/__tests__/**", | ||
"**/*.spec.ts", | ||
"**/*.spec.tsx", | ||
"**/*.test.ts", | ||
"**/*.test.tsx" | ||
], | ||
"compilerOptions": { | ||
"module": "ESNext", | ||
"lib": ["DOM", "ESNext"], | ||
// output .d.ts declaration files for consumers | ||
"declaration": true, | ||
// output .d.ts declaration files only (esbuild will transpile to .js for us) | ||
"emitDeclarationOnly": true, | ||
// stricter type-checking for stronger correctness. Recommended by TS | ||
"strict": true, | ||
// linter checks for common issues | ||
"noImplicitReturns": true, | ||
"noFallthroughCasesInSwitch": true, | ||
// noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative | ||
"noUnusedLocals": true, | ||
"noUnusedParameters": true, | ||
// use modern Node's module resolution algorithm, instead of the legacy TS one | ||
"moduleResolution": "NodeNext", | ||
// transpile JSX to React.createElement | ||
"jsx": "react", | ||
// interop between ESM and CJS modules. Recommended by TS | ||
"esModuleInterop": true, | ||
// significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS | ||
"skipLibCheck": true, | ||
// error out if import and file system have a casing mismatch. Recommended by TS | ||
"forceConsistentCasingInFileNames": true, | ||
// esbuild transpiles files individually, so ensure each file is valid when isolated | ||
"isolatedModules": true | ||
} | ||
} |
Oops, something went wrong.