diff --git a/.gitignore b/.gitignore index be267c21..75556de7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ npm-debug.log node_modules/ bin/ +/esm/ apis-config/ \ No newline at end of file diff --git a/buildpackage.js b/buildpackage.js index e9ad1fd9..a8174c51 100644 --- a/buildpackage.js +++ b/buildpackage.js @@ -13,13 +13,16 @@ const UglifyES = require("uglify-es"); (async function() { // Clean bin directory - console.log("# Cleaning bin. Running shelljs rm -rf ./bin"); - shell.rm("-rf", "./bin"); + console.log("# Cleaning bin/ and esm/. Running shelljs rm -rf ./bin ./esm"); + shell.rm("-rf", "./bin", "./esm"); - // Compile typescript - console.log("# Compiling TypeScript. Executing `node_modules\\.bin\\tsc -p ./tsconfig.json`."); + // On Windows, we need `\`, on Unix we need `/`. + const tsc = path.join("node_modules", ".bin", "tsc"); + + // Compile typescript ./bin folder + console.log(`# Compiling TypeScript. Executing \`${tsc} -p ./tsconfig.json\`.`); try { - execSync("node_modules\\.bin\\tsc -p ./tsconfig.json", { + execSync(`${tsc} -p ./tsconfig.json`, { stdio: [0, 1, 2], shell: true, cwd: __dirname, @@ -29,18 +32,24 @@ const UglifyES = require("uglify-es"); process.exit(1); } - // Copy ts files to bin - console.log("# Copy declare files to bin."); + // Compile typescript ./esm folder + console.log(`# Compiling TypeScript to ESM. Executing \`${tsc} -p ./tsconfig.esm.json\`.`); try { - await copy(path.join(__dirname, "src"), path.join(__dirname, "bin"), { - filter: f => { - return f.endsWith(".d.ts"); - }, + execSync(`${tsc} -p ./tsconfig.esm.json`, { + stdio: [0, 1, 2], + shell: true, + cwd: __dirname, }); - } catch (e) { - console.log("Copy failed. " + error); + } catch (error) { + console.log("ERROR: Failed to build TypeScript ESM."); + process.exit(1); } - + console.log("# Creating ./esm/package.json to show files in ./esm are ESM"); + fs.writeFileSync("./esm/package.json", '{"type": "module"}\n'); + // Move ./esm folder into ./bin/esm + console.log("# Moving ./esm folder to ./bin/esm"); + fs.renameSync("./esm", "./bin/esm"); + // Uglify JavaScript console.log("# Minifying JS using the UglifyES API, replacing un-minified files."); let count = 0; @@ -56,7 +65,7 @@ const UglifyES = require("uglify-es"); }); for (const file of files) { - if (file.includes("node_modules/")) { + if (file.includes("node_modules/") || file.includes("esm/")) { continue; } fs.writeFileSync( diff --git a/generateExports.js b/generateExports.js new file mode 100644 index 00000000..8645c736 --- /dev/null +++ b/generateExports.js @@ -0,0 +1,41 @@ +const fs = require("fs"); + +const srcDir = "src"; +const esmDir = "esm"; + +// Read all subdirectories in src +const entries = fs.readdirSync(srcDir, { withFileTypes: true }); +const folders = entries.filter((e) => e.isDirectory()).map((e) => e.name); + +// Base exports +const exportsField = { + ".": { + import: `./${esmDir}/index.js`, + default: "./index.js", + }, + "./*": { + import: `./${esmDir}/*/index.js`, + default: "./*/index.js", + }, + "./package.json": "./package.json", +}; + +// Add exports for each subfolder +for (const folder of folders) { + exportsField[`./${folder}/*`] = { + import: `./${esmDir}/${folder}/*.js`, + default: `./${folder}/*.js`, + }; + exportsField[`./${folder}/*.js`] = { + import: `./${esmDir}/${folder}/*.js`, + default: `./${folder}/*.js`, + }; +} + +// Update package.json +const pkgPath = "package.json"; +const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8")); +pkg.exports = exportsField; +fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2)); + +console.log("✅ package.json exports updated from src/"); diff --git a/package.json b/package.json index 7f3a00ab..a6d40a2d 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,10 @@ "type": "git", "url": "https://github.com/Microsoft/azure-devops-extension-api.git" }, + "type": "module", "scripts": { + "generate:exports": "node generateExports.js", + "prepare": "npm run generate:exports && tsc --project tsconfig.esm.json", "build": "node buildpackage.js" }, "keywords": [ @@ -21,7 +24,8 @@ }, "homepage": "https://docs.microsoft.com/en-us/azure/devops/integrate", "dependencies": { - "whatwg-fetch": "~3.0.0" + "whatwg-fetch": "~3.0.0", + "azure-devops-extension-sdk": "^4.0.2" }, "peerDependencies": { "azure-devops-extension-sdk": "^2 || ^3 || ^4" diff --git a/src/Boards/BoardsClient.ts b/src/Boards/BoardsClient.ts index 33e36436..f4b18899 100644 --- a/src/Boards/BoardsClient.ts +++ b/src/Boards/BoardsClient.ts @@ -7,7 +7,7 @@ import { IVssRestClientOptions } from "../Common/Context"; import { RestClientBase } from "../Common/RestClientBase"; -import Boards = require("../Boards/Boards"); +import * as Boards from '../Boards/Boards'; export class BoardsRestClient extends RestClientBase { constructor(options: IVssRestClientOptions) { diff --git a/src/Common/Context.d.ts b/src/Common/Context.ts similarity index 100% rename from src/Common/Context.d.ts rename to src/Common/Context.ts diff --git a/tsconfig.esm.json b/tsconfig.esm.json new file mode 100644 index 00000000..4492a99f --- /dev/null +++ b/tsconfig.esm.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "target": "es2015", + "rootDir": "src/", + "outDir": "esm/", + "module": "es2015", + } +} \ No newline at end of file