Skip to content

feat(build-tools): Add generate:source:entrypoints command#22895

Closed
sonalideshpandemsft wants to merge 39 commits into
microsoft:mainfrom
sonalideshpandemsft:fix-vscode-auto-imports-build-tools
Closed

feat(build-tools): Add generate:source:entrypoints command#22895
sonalideshpandemsft wants to merge 39 commits into
microsoft:mainfrom
sonalideshpandemsft:fix-vscode-auto-imports-build-tools

Conversation

@sonalideshpandemsft
Copy link
Copy Markdown
Contributor

@sonalideshpandemsft sonalideshpandemsft commented Oct 24, 2024

Original PR: https://github.com/microsoft/FluidFramework/pull/22872/files.

The original PR generates source entry points for the odsp-client and datastore-definitions package.

This PR includes only the build-tools changes from the original PR. It introduces a new command, GenerateSourceEntrypointsCommand, which generates source entry points under src/entrypoints.

Once this PR is merged, there will be three additional PRs:

  1. A new command to generate node10 compat entrypoints: feat(build-tools): Add generate:node10Entrypoints command #22937
  2. An update to the build tools to the new version that includes these changes.
  3. PR to update the Fluid build configuration and package.json: Update fluid build config #22896

@github-actions github-actions Bot added base: main PRs targeted against main branch area: build Build related issues dependencies Pull requests that update a dependency file labels Oct 24, 2024
@sonalideshpandemsft sonalideshpandemsft force-pushed the fix-vscode-auto-imports-build-tools branch from d5d683b to ade66c5 Compare October 25, 2024 17:23
@sonalideshpandemsft sonalideshpandemsft force-pushed the fix-vscode-auto-imports-build-tools branch from ade66c5 to 8dbad63 Compare October 25, 2024 17:28
@github-actions github-actions Bot removed the dependencies Pull requests that update a dependency file label Oct 25, 2024
@sonalideshpandemsft sonalideshpandemsft force-pushed the fix-vscode-auto-imports-build-tools branch from cf9cd32 to fbe8d00 Compare October 25, 2024 18:38
@sonalideshpandemsft sonalideshpandemsft changed the title Add tool to generate source and node10 compat entrypoints Add generate:source:entrypoints command and node10 compat entrypoints Oct 25, 2024
@sonalideshpandemsft sonalideshpandemsft marked this pull request as ready for review October 25, 2024 18:46
Copy link
Copy Markdown
Member

@tylerbutler tylerbutler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My biggest concerns are the location of the command (it should be in the commands folder) and the added complexity to the build process. How will fluid-build handle these new tasks? How many more tasks will this introduce? We can address those in other PRs but I worry that this will complicate and/or slow down the build quite a bit.

Also is there a reason this command isn't a PackageCommand? It seems like a lot of the boilerplate code could be removed or simplified that way. You're always operating at the package level so the json parsing etc. could be done for you. Look at generate:typetests for an example. You can still have a per-package build task (again typetests are an example).

Comment thread build-tools/packages/build-cli/src/commands/generate/source-entrypoints.ts Outdated
Comment thread build-tools/packages/build-cli/src/library/commands/generateSourceEntrypoints.ts Outdated
Comment thread build-tools/packages/build-cli/docs/generate.md Outdated
Comment thread build-tools/packages/build-cli/docs/generate.md
Comment thread build-tools/packages/build-cli/src/library/commands/generateSourceEntrypoints.ts Outdated
Comment thread build-tools/packages/build-cli/src/library/commands/generateSourceEntrypoints.ts Outdated
mapSrcApiTagLevelToOutput: Map<ApiTag, ExportData>;
} {
let emitDeclarationOnly: boolean = false;
if (tsconfig.compilerOptions?.emitDeclarationOnly !== undefined) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If emitDeclarationOnly is set to true in the tsconfig, the types field should be referenced, as the default field may not be present. For example, datastore-definitions only emits type declarations.

https://github.com/microsoft/FluidFramework/blob/main/packages/runtime/datastore-definitions/package.json#L18
https://github.com/microsoft/FluidFramework/blob/main/packages/runtime/datastore-definitions/tsconfig.json#L8

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused - what is driving the decision of what files to create and what files to read as input? I thought it was using the index.ts file to decide what the API levels in use are. Is it reading the package.json exports to determine that? Seems like there should be one input - the list of all exports. Why does the types or default field matter?

* @param logger - optional Logger
* @returns object with mapKeyToOutput.
*/
export function queryDefaultResolutionPathsFromPackageExports<TOutKey>(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function seems like it is replicating the exports resolution algorithm. We can just use that resolution logic directly. See use of resolve.imports elsewhere.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to an earlier comment - it's confusing me when we read from the exports field if we are also reading from index.ts to find the exports. Maybe a high level bulleted list of the steps would help? I thought it was:

  • Open the file passed into the CLI to find the full list of exports.
  • Determine what API levels are exported using the data from the previous step.
  • Create a TS file with the exports for the appropriate level.

* @param emitDeclarationOnly -If true, "types" exports are considered.
* @returns matching export data and matching query entry value as outKey property
*/
function findDefaultPathsMatching<TOutKey>(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should definitely be replaceable with resolve.imports.

Comment thread build-tools/packages/build-cli/src/library/packageExports.ts Outdated
Comment thread build-tools/packages/build-cli/src/library/packageExports.ts Outdated
Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
Copy link
Copy Markdown
Contributor

@jason-ha jason-ha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't able to get through everything. But here are some comments.

Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
@sonalideshpandemsft sonalideshpandemsft force-pushed the fix-vscode-auto-imports-build-tools branch 2 times, most recently from 9290864 to bd2ceb1 Compare November 5, 2024 15:40
@sonalideshpandemsft sonalideshpandemsft force-pushed the fix-vscode-auto-imports-build-tools branch from bd2ceb1 to cb1a30f Compare November 5, 2024 15:43
Copy link
Copy Markdown
Contributor

@jason-ha jason-ha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two more pieces missing to make this a replacement for the existing code:

  1. [previously noted] needs a task helper - see build-tools/packages/build-tools/src/fluidBuild/tasks/taskFactory.ts with "flub generate entrypoints": GenerateEntrypointsTask,
  2. the output files need added into build database smarts: see build-tools/packages/build-cli/src/library/repoPolicyCheck/fluidBuildDatabase.ts's flubOutput that looks for "flub generate entrypoints". It looks like it needs a new case for "flub generate sourceEntrypoints".

The prior node10 change is probably missing similar. I am guessing node10 stuff can skip item 2 as we don't use those outputs ourselves.

* (as opposed to a separate \@types package).
*/
export function getTypesPathFromPackage(
export function getExportPathFromPackage(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a lot left in here that is still "types" specific. There are comments and error messages and variable names.
I love reuse, but it needs cleaned up.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I still see lots of "types" strings in this code.

export function getExportPathFromPackage(
packageJson: PackageJson,
level: ApiLevel,
conditions: string[],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think a generic array of strings is okay here. ["types"] is definitely okay. Looks like you tested some cases with ["default"]. So you could accept those specifically.
Curious if [] also works in place of ["default"].

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, empty array falls back to default

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do update the typing to reflect the values that are okay.

Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
Comment on lines +141 to +142
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const { rootDir, outDir, emitDeclarationOnly } = compilerOptions;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So many unsafe assignment disables - needs some comments

Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
Comment on lines +381 to +382
log.info(`\tGenerating ${outFile}`);
const sourceFile = project.createSourceFile(outFile, undefined, {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic should have some lines to create the target directory if it doesn't exist.
(It is getting by since current use expects tsconfig next to the target source location.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I have seen this create an output directory if one does not exist irrespective of tsconfig

Comment thread build-tools/packages/build-cli/src/commands/generate/sourceEntrypoints.ts Outdated
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const { rootDir, outDir, emitDeclarationOnly } = compilerOptions;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we need emitDeclarationOnly (alternative would be to retry with "types" when "default" gives us nothing), then we really want tsconfig extends processing. (I commented, I think, in the usage example PR that it is not good to duplicate settings. It is going to get messed up by humans.)
I expect that rootDir and outDir are usually present based on how we usually write things and not in danger.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

build-tools/packages/build-cli/src/library/repoPolicyCheck/fluidBuildDatabase.ts's tscOutput contains all the smarts for accurately deriving tsc options including rootDir and outDir. (You would likely give tscUtils.parseCommandLine fake command line tsc --project <tsconfigPath> to get results.)

Copy link
Copy Markdown
Contributor Author

@sonalideshpandemsft sonalideshpandemsft Nov 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading emitDeclarationOnly simplifies concluding if the package is types only. resolve.exports have options to first check default and then types but that makes reading types only value difficult/messy.

@sonalideshpandemsft sonalideshpandemsft force-pushed the fix-vscode-auto-imports-build-tools branch from 2df78e3 to bd6c5db Compare November 19, 2024 13:04
@sonalideshpandemsft sonalideshpandemsft force-pushed the fix-vscode-auto-imports-build-tools branch from 39f0a6e to 6f389e3 Compare November 22, 2024 20:20
@sonalideshpandemsft sonalideshpandemsft force-pushed the fix-vscode-auto-imports-build-tools branch from b08ccf1 to a27ab9a Compare November 24, 2024 14:27
@sonalideshpandemsft sonalideshpandemsft force-pushed the fix-vscode-auto-imports-build-tools branch from a27ab9a to edfcb69 Compare November 24, 2024 14:37
Comment on lines 188 to 190
const outDir = options.outDir ?? ".";

const inputRegex = /(?:\.d)?(\.[cm]?ts)$/;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not an issue - just noticed so calling it out - intentional added blank line here?

Comment on lines +9 to +18
export class GenerateSourceEntrypointsTask extends TscDependentTask {
protected get configFileFullPaths() {
// Add package.json, which tsc should also depend on, but currently doesn't.
return [this.node.pkg.packageJsonFileName];
}

protected async getToolVersion() {
return getInstalledPackageVersion("@fluid-tools/build-cli", this.node.pkg.directory);
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this handle its output files? Looks like if we deleted one it wouldn't impact this task's sense of being complete, i.e. it wouldn't rerun using fluib-build.
(The other task took a shortcut for specifically specifying output files because there was nothing else in the system that depended on them but was still a problem if someone altered the output expect task to rerun on rebuild.)

log: Logger,
fallbackEntrypoint?: ApiLevel,
): { typesPath: string; entrypointUsed: ApiLevel } {
const getTypesPath = (level: ApiLevel): string | undefined => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer function getTypesPath(level: ApiLevel): string | undefined { to get named function.

Comment on lines +257 to +260
* @param conditions - Export conditions to apply. Fallback to `default` if no condition is passed
* @returns A package relative path.
*/
export function getTypesPathFromPackage(
export function getExportPathFromPackage(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use of this seems incorrect (fallible). When I looked at this a while back it didn't feel familiar, and something felt off. We can get away with using this for node10 and probably for type tests. Node10 has narrow "conditions". Typetests are also narrowly focused on an entrypoint and just types.
Some packages have conditions that are beyond "default" and "types". That is why the prior version of things does not use resolve.exports package which requires you to know the conditions. Instead, we want to find all of the paths under an export given the generation criteria and get their conditions. It was queryTypesResolutionPathsFromPackageExports that I was expecting a generic form of or to be adapted away from strictly for "types" conditions. (Would have matched the original command.)
Probably this pattern is why some other cases seem hard to account for - like stopping automatic generation of a file temporarily.
I need to think about this.

@microsoft-github-policy-service
Copy link
Copy Markdown
Contributor

This PR has been automatically marked as stale because it has had no activity for 60 days. It will be closed if no further activity occurs within 8 days of this comment. Thank you for your contributions to Fluid Framework!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: build Build related issues base: main PRs targeted against main branch status: stale

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants