-
Notifications
You must be signed in to change notification settings - Fork 12k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(@angular-devkit/build-angular): integrate Angular compiler linker
The newly introduced library linker mode that removes the need for ngcc is integrated into the Angular CLI's build system. This allows libraries that are built in linker mode to be used when building an application.
- Loading branch information
1 parent
48c4393
commit 35d8adf
Showing
4 changed files
with
195 additions
and
28 deletions.
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
packages/angular_devkit/build_angular/src/babel/babel-loader.d.ts
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,24 @@ | ||
/** | ||
* @license | ||
* Copyright Google Inc. All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
declare module 'babel-loader' { | ||
type BabelLoaderCustomizer<T> = ( | ||
babel: typeof import('@babel/core'), | ||
) => { | ||
customOptions?( | ||
this: import('webpack').loader.LoaderContext, | ||
loaderOptions: Record<string, unknown>, | ||
loaderArguments: { source: string; map?: unknown }, | ||
): Promise<{ custom?: T; loader: Record<string, unknown> }>; | ||
config?( | ||
this: import('webpack').loader.LoaderContext, | ||
configuration: import('@babel/core').PartialConfig, | ||
loaderArguments: { source: string; map?: unknown; customOptions: T }, | ||
): import('@babel/core').TransformOptions; | ||
}; | ||
function custom<T>(customizer: BabelLoaderCustomizer<T>): import('webpack').loader.Loader; | ||
} |
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
120 changes: 120 additions & 0 deletions
120
packages/angular_devkit/build_angular/src/babel/webpack-loader.ts
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,120 @@ | ||
/** | ||
* @license | ||
* Copyright Google Inc. All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
import { custom } from 'babel-loader'; | ||
|
||
interface AngularCustomOptions { | ||
forceES5: boolean; | ||
shouldLink: boolean; | ||
} | ||
|
||
/** | ||
* Cached linker check utility function | ||
* | ||
* If undefined, not yet been imported | ||
* If null, attempted import failed and no linker support | ||
* If function, import succeeded and linker supported | ||
*/ | ||
let needsLinking: undefined | null | typeof import('@angular/compiler-cli/linker').needsLinking; | ||
|
||
async function checkLinking( | ||
path: string, | ||
source: string, | ||
): Promise<{ hasLinkerSupport?: boolean; requiresLinking: boolean }> { | ||
// @angular/core and @angular/compiler will cause false positives | ||
if (/[\\\/]@angular[\\\/](?:compiler|core)/.test(path)) { | ||
return { requiresLinking: false }; | ||
} | ||
|
||
if (needsLinking !== null) { | ||
try { | ||
if (needsLinking === undefined) { | ||
needsLinking = (await import('@angular/compiler-cli/linker')).needsLinking; | ||
} | ||
|
||
// If the linker entry point is present then there is linker support | ||
return { hasLinkerSupport: true, requiresLinking: needsLinking(path, source) }; | ||
} catch { | ||
needsLinking = null; | ||
} | ||
} | ||
|
||
// Fallback for Angular versions less than 11.1.0 with no linker support. | ||
// This information is used to issue errors if a partially compiled library is used when unsupported. | ||
return { | ||
hasLinkerSupport: false, | ||
requiresLinking: | ||
source.includes('ɵɵngDeclareDirective') || source.includes('ɵɵngDeclareComponent'), | ||
}; | ||
} | ||
|
||
export default custom<AngularCustomOptions>(() => { | ||
const baseOptions = Object.freeze({ | ||
babelrc: false, | ||
configFile: false, | ||
compact: false, | ||
cacheCompression: false, | ||
sourceType: 'unambiguous', | ||
}); | ||
|
||
return { | ||
async customOptions({ forceES5, ...loaderOptions }, { source }) { | ||
let shouldProcess = forceES5; | ||
|
||
let shouldLink = false; | ||
const { hasLinkerSupport, requiresLinking } = await checkLinking(this.resourcePath, source); | ||
if (requiresLinking && !hasLinkerSupport) { | ||
// Cannot link if there is no linker support | ||
this.emitError( | ||
'File requires the Angular linker. "@angular/compiler-cli" version 11.1.0 or greater is needed.', | ||
); | ||
} else { | ||
shouldLink = requiresLinking; | ||
} | ||
shouldProcess ||= shouldLink; | ||
|
||
const options: Record<string, unknown> = { | ||
...baseOptions, | ||
...loaderOptions, | ||
}; | ||
|
||
if (!shouldProcess) { | ||
// Force the current file to be ignored | ||
options.ignore = [() => true]; | ||
} | ||
|
||
return { custom: { forceES5: !!forceES5, shouldLink }, loader: options }; | ||
}, | ||
config(configuration, { customOptions }) { | ||
return { | ||
...configuration.options, | ||
presets: [ | ||
...(configuration.options.presets || []), | ||
[ | ||
require('./presets/application').default, | ||
{ | ||
angularLinker: customOptions.shouldLink, | ||
forceES5: customOptions.forceES5, | ||
diagnosticReporter: (type, message) => { | ||
switch (type) { | ||
case 'error': | ||
this.emitError(message); | ||
break; | ||
case 'info': | ||
// Webpack does not currently have an informational diagnostic | ||
case 'warning': | ||
this.emitWarning(message); | ||
break; | ||
} | ||
}, | ||
} as import('./presets/application').ApplicationPresetOptions, | ||
], | ||
], | ||
}; | ||
}, | ||
}; | ||
}); |
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