Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 52b8c59

Browse files
Cephyric-ghpieh
andauthored
feat: adds support for detecting NX monorepos (#263)
* feat: adds support for detecting NX monorepos * fix: adds server.ts files from NX monorepo builds to tools folder * feat: changes NX project.json detection to rely on the user config for their package path * fix: fix fail message to correctly reference project.json Co-authored-by: Michal Piechowiak <misiek.piechowiak@gmail.com> * fix: remove unnecessary reference to selectedProject --------- Co-authored-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
1 parent f5b8803 commit 52b8c59

File tree

79 files changed

+46544
-30
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+46544
-30
lines changed

‎.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,5 @@ Temporary Items
143143

144144
.netlify
145145
.angular
146+
.nx
147+
.idea

‎package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
"pretest:fixtures:angular-19-common-engine": "cd tests/fixtures/angular-19-common-engine && npm ci",
4848
"pretest:fixtures:angular-19-app-engine": "cd tests/fixtures/angular-19-app-engine && npm ci",
4949
"pretest:fixtures:angular-19-prerender-false": "cd tests/fixtures/angular-19-prerender-false && npm ci",
50+
"pretest:fixtures:nx-angular-19-common-engine": "cd tests/fixtures/nx-angular-19-common-engine && npm ci",
51+
"pretest:fixtures:nx-angular-19-app-engine": "cd tests/fixtures/nx-angular-19-app-engine && npm ci",
5052
"pretest": "run-s pretest:*",
5153
"test": "node --test"
5254
},

‎src/helpers/fixOutputDir.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,25 @@ const { join } = require('path')
33
const getAngularJson = require('./getAngularJson')
44
const { getProject } = require('./setUpEdgeFunction')
55

6-
const fixOutputDir = async function ({ failBuild, failPlugin, siteRoot, PUBLISH_DIR, IS_LOCAL, netlifyConfig }) {
7-
const angularJson = getAngularJson({ failPlugin, siteRoot })
8-
const project = getProject(angularJson, failBuild)
6+
const fixOutputDir = async function ({
7+
failBuild,
8+
failPlugin,
9+
siteRoot,
10+
PUBLISH_DIR,
11+
IS_LOCAL,
12+
netlifyConfig,
13+
workspaceType,
14+
packagePath,
15+
}) {
16+
const angularJson = getAngularJson({ failPlugin, siteRoot, workspaceType, packagePath })
17+
const project = getProject(angularJson, failBuild, workspaceType === 'nx')
918

10-
const { outputPath } = project.architect.build.options
19+
const { outputPath } = workspaceType==='nx' ? project.targets.build.options : project.architect.build.options
1120

12-
const isApplicationBuilder = project.architect.build.builder.endsWith(':application')
21+
const isApplicationBuilder =
22+
workspaceType === 'nx'
23+
? project.targets.build.executor.endsWith(':application')
24+
: project.architect.build.builder.endsWith(':application')
1325
const correctPublishDir = isApplicationBuilder ? join(outputPath, 'browser') : outputPath
1426
if (correctPublishDir === PUBLISH_DIR) {
1527
return

‎src/helpers/getAngularJson.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const { join } = require('node:path')
2+
const process = require('process')
23

34
const { existsSync, readJsonSync } = require('fs-extra')
45

@@ -7,10 +8,30 @@ const { existsSync, readJsonSync } = require('fs-extra')
78
* @param {Object} obj
89
* @param {string} obj.siteRoot Root directory of an app
910
* @param {(msg: string) => never} obj.failPlugin Function to fail the plugin
11+
* @param {'nx' | 'default'} obj.workspaceType Type of monorepo, dictates what json file to open
12+
* @param {string} obj.packagePath The path to the package directory
1013
*
1114
* @returns {any}
1215
*/
13-
const getAngularJson = function ({ failPlugin, siteRoot }) {
16+
const getAngularJson = function ({ failPlugin, siteRoot, workspaceType, packagePath }) {
17+
if (workspaceType === 'nx') {
18+
if ((packagePath ?? '').length === 0) {
19+
return failPlugin(
20+
`packagePath must be set to the location of the project.json being built when deploying an NX monorepo, e.g. "apps/{project-name}"`,
21+
)
22+
}
23+
24+
if (!existsSync(join(siteRoot, packagePath, 'project.json'))) {
25+
return failPlugin(`No project.json found in ${packagePath}`)
26+
}
27+
28+
try {
29+
return readJsonSync(join(siteRoot, packagePath, 'project.json'))
30+
} catch {
31+
return failPlugin(`Could not parse the contents of project.json`)
32+
}
33+
}
34+
1435
if (!existsSync(join(siteRoot, 'angular.json'))) {
1536
return failPlugin(`No angular.json found at project root`)
1637
}

‎src/helpers/getAngularRoot.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,33 @@ const process = require('process')
55
/**
66
* If we're in a monorepo then the site root may not be the same as the base directory
77
* If there's no angular.json in the root, we instead look for it 2 levels up from the publish dir
8+
*
9+
* @returns {{siteRoot: string, workspaceType: 'nx' | 'default'}}
810
*/
911
const getAngularRoot = ({ failBuild, netlifyConfig }) => {
1012
let angularRoot = process.cwd()
13+
14+
// This could be an NX repo, so check for the existence of nx.json too
15+
let angularJsonExists = existsSync(path.join(angularRoot, 'angular.json'))
16+
let nxJsonExists = existsSync(path.join(angularRoot, 'nx.json'))
17+
1118
if (
12-
!existsSync(path.join(angularRoot, 'angular.json')) &&
19+
!angularJsonExists &&
20+
!nxJsonExists &&
1321
netlifyConfig.build.publish &&
1422
netlifyConfig.build.publish !== angularRoot
1523
) {
1624
angularRoot = path.dirname(path.resolve(path.join(netlifyConfig.build.publish, '..', '..')))
25+
angularJsonExists = existsSync(path.join(angularRoot, 'angular.json'))
26+
nxJsonExists = existsSync(path.join(angularRoot, 'nx.json'))
1727

18-
if (!existsSync(path.join(angularRoot,'angular.json'))) {
28+
if (!angularJsonExists&&!nxJsonExists) {
1929
return failBuild(
20-
`Could not locate your angular.json at your project root or two levels above your publish directory. Make sure your publish directory is set to "{PATH_TO_YOUR_SITE}/dist/{YOUR_PROJECT_NAME}/browser", where {YOUR_PROJECT_NAME} is 'defaultProject' in your angular.json.`,
30+
`Could not locate your angular.json/nx.json at your project root or two levels above your publish directory. Make sure your publish directory is set to "{PATH_TO_YOUR_SITE}/dist/{YOUR_PROJECT_NAME}/browser", where {YOUR_PROJECT_NAME} is 'defaultProject' in your angular.json.`,
2131
)
2232
}
2333
}
24-
return angularRoot
34+
return {siteRoot: angularRoot,workspaceType: nxJsonExists ? 'nx' : 'default'}
2535
}
2636

2737
module.exports = getAngularRoot

‎src/helpers/knownServerTsSignatures.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@
44
"0e451aa946aca10c9d6782ac008748fcd39236d3ad1cc9868100a2981105e010": "CommonEngine",
55
"577f7bc87c16bd10bac499e228ef24d23dc4dd516e469b5db3eefae4edcf6345": "CommonEngine",
66
"5678601ed12556305074503967b44ae42c45c268579db057c25cbf4b21a7212e": "CommonEngine",
7-
"76419eb94b4b8672ba3bd79d34c5a66c7c30ff173995ecc6e0adc5808b86822d": "AppEngine"
7+
"33d360cdf4819d90afeecd49952241191ee490900fa919a46f990186be3e8b5f": "CommonEngine",
8+
"76419eb94b4b8672ba3bd79d34c5a66c7c30ff173995ecc6e0adc5808b86822d": "AppEngine",
9+
"a5aad843a116e34ce61264117cba981cff5eea3e6672815a4db08e7b4e5599d6": "AppEngine"
810
}

‎src/helpers/serverModuleHelpers.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,22 +95,22 @@ const guessUsedEngine = function (serverModuleContents) {
9595
* @param {string} obj.angularVersion Angular version
9696
* @param {string} obj.siteRoot Root directory of an app
9797
* @param {(msg: string) => never} obj.failPlugin Function to fail the plugin
98+
* @param {'nx' | 'default'} obj.workspaceType The workspace type being parsed
99+
* @param {string} obj.packagePath The path to the package directory
98100
* * @param {(msg: string) => never} obj.failBuild Function to fail the build
99101
*
100102
* @returns {'AppEngine' | 'CommonEngine' | undefined}
101103
*/
102-
const fixServerTs = async function ({ angularVersion, siteRoot, failPlugin, failBuild }) {
104+
const fixServerTs = async function ({ angularVersion, siteRoot, failPlugin, failBuild, workspaceType, packagePath }) {
103105
if (!satisfies(angularVersion, '>=19.0.0-rc', { includePrerelease: true })) {
104106
// for pre-19 versions, we don't need to do anything
105107
return
106108
}
107109

108-
const angularJson = getAngularJson({ failPlugin, siteRoot })
110+
const angularJson = getAngularJson({ failPlugin, siteRoot, workspaceType, packagePath })
109111

110-
const project = getProject(angularJson, failBuild)
111-
const {
112-
architect: { build },
113-
} = project
112+
const project = getProject(angularJson, failBuild, workspaceType === 'nx')
113+
const build = workspaceType === 'nx' ? project.targets.build : project.architect.build
114114

115115
serverModuleLocation = build?.options?.ssr?.entry
116116
if (!serverModuleLocation || !existsSync(serverModuleLocation)) {
@@ -131,7 +131,7 @@ const fixServerTs = async function ({ angularVersion, siteRoot, failPlugin, fail
131131
)
132132
}
133133

134-
// check wether project is using stable CommonEngine or Developer Preview AppEngine
134+
// check whether project is using stable CommonEngine or Developer Preview AppEngine
135135
const serverModuleContents = await readFile(serverModuleLocation, 'utf8')
136136

137137
const usedEngineBasedOnKnownSignatures = getEngineBasedOnKnownSignatures(serverModuleContents)

‎src/helpers/setUpEdgeFunction.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,13 @@ const getAllFilesIn = (dir) =>
2222

2323
const toPosix = (path) => path.split(sep).join(posix.sep)
2424

25-
const getProject = (angularJson, failBuild) => {
25+
const getProject = (angularJson, failBuild,isNxWorkspace=false) => {
2626
const selectedProject = process.env.ANGULAR_PROJECT
27+
28+
if (isNxWorkspace) {
29+
return angularJson
30+
}
31+
2732
if (selectedProject) {
2833
const project = angularJson.projects[selectedProject]
2934
if (!project) {
@@ -98,7 +103,7 @@ const setUpEdgeFunction = async ({ outputDir, constants, failBuild, usedEngine }
98103
const document = Buffer.from(${JSON.stringify(
99104
Buffer.from(html, 'utf-8').toString('base64'),
100105
)}, 'base64').toString("utf-8");
101-
106+
102107
export default async (request, context) => {
103108
const html = await renderApplication(bootstrap, {
104109
url: request.url,
@@ -155,7 +160,7 @@ const setUpEdgeFunction = async ({ outputDir, constants, failBuild, usedEngine }
155160
// reading file is needed for inlining CSS, but failing to do so is
156161
// not causing fatal error so we just ignore it here
157162
}
158-
163+
159164
return originalReadFile.apply(globalThis.Deno, args)
160165
}
161166
} catch {
@@ -194,7 +199,7 @@ const setUpEdgeFunction = async ({ outputDir, constants, failBuild, usedEngine }
194199
ssrFunctionContent = /* javascript */ `
195200
import { netlifyAppEngineHandler } from "${toPosix(relative(edgeFunctionDir, serverDistRoot))}/server.mjs";
196201
import "./fixup-event.mjs";
197-
202+
198203
export default netlifyAppEngineHandler;
199204
`
200205
}

‎src/index.js

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ let usedEngine
1616
module.exports = {
1717
async onPreBuild({ netlifyConfig, utils, constants }) {
1818
const { failBuild, failPlugin } = utils.build
19-
const siteRoot = getAngularRoot({ failBuild, netlifyConfig })
19+
const {siteRoot, workspaceType } = getAngularRoot({ failBuild, netlifyConfig })
2020
const angularVersion = await getAngularVersion(siteRoot)
2121
isValidAngularProject = validateAngularVersion(angularVersion)
2222

@@ -36,9 +36,18 @@ module.exports = {
3636
PUBLISH_DIR: constants.PUBLISH_DIR,
3737
IS_LOCAL: constants.IS_LOCAL,
3838
netlifyConfig,
39+
workspaceType,
40+
packagePath: constants.PACKAGE_PATH,
3941
})
4042

41-
usedEngine = await fixServerTs({ angularVersion, siteRoot, failPlugin, failBuild })
43+
usedEngine = await fixServerTs({
44+
angularVersion,
45+
siteRoot,
46+
failPlugin,
47+
failBuild,
48+
workspaceType,
49+
packagePath: constants.PACKAGE_PATH,
50+
})
4251
},
4352
async onBuild({ utils, netlifyConfig, constants }) {
4453
await revertServerTsFix()
@@ -48,13 +57,11 @@ module.exports = {
4857

4958
const { failBuild, failPlugin } = utils.build
5059

51-
const siteRoot= getAngularRoot({ failBuild, netlifyConfig })
52-
const angularJson = getAngularJson({ failPlugin, siteRoot })
60+
const {siteRoot, workspaceType }= getAngularRoot({ failBuild, netlifyConfig,onBuild: true })
61+
const angularJson = getAngularJson({ failPlugin, siteRoot, workspaceType,packagePath: constants.PACKAGE_PATH })
5362

54-
const project = getProject(angularJson, failBuild)
55-
const {
56-
architect: { build },
57-
} = project
63+
const project = getProject(angularJson, failBuild, workspaceType === 'nx')
64+
const build = workspaceType === 'nx' ? project.targets.build : project.architect.build
5865
const outputDir = build?.options?.outputPath
5966
if (!outputDir || !existsSync(outputDir)) {
6067
return failBuild('Could not find build output directory')
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Editor configuration, see https://editorconfig.org
2+
root = true
3+
4+
[*]
5+
charset = utf-8
6+
indent_style = space
7+
indent_size = 2
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
11+
[*.ts]
12+
quote_type = single
13+
ij_typescript_use_double_quotes = false
14+
15+
[*.md]
16+
max_line_length = off
17+
trim_trailing_whitespace = false

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /