Angular Build Cache: Optimizing Your Build Process
Angular projects can become large and complex, leading to lengthy build times. A build cache can significantly speed up development by reusing previously compiled artifacts when code hasn't changed. This challenge focuses on implementing a basic build cache mechanism for a simplified Angular-like compilation process.
Problem Description
Your task is to create a TypeScript function that simulates an Angular build process with caching. The function should accept a list of "Angular modules" (represented as strings for simplicity), compile them if they are new or have changed, and return the compiled output. A cache should be maintained to store the compiled output of modules. If a module has already been compiled and its content hasn't changed, the cached version should be returned instead of recompiling.
Key Requirements:
- Module Compilation: Simulate a compilation process that takes a module's source code (string) and produces a compiled output (string). For this challenge, assume a simple transformation like prefixing "compiled: " to the module's content.
- Caching: Maintain an in-memory cache (e.g., a Map or an object) to store compiled modules. The key for the cache should be the module's identifier (its source code string in this simplified case).
- Cache Hit/Miss: When a module is requested for compilation:
- If the module is in the cache and its content is identical to the cached version, return the cached compiled output.
- If the module is not in the cache, or if its content has changed (though for this simplified problem, we'll assume the input string is the definitive representation, so changes are implicitly handled by providing a new string), compile it, store the result in the cache, and return the compiled output.
- Multiple Modules: The build process should handle an array of module inputs.
Expected Behavior:
The function should process a list of modules. For each module, it should decide whether to recompile or use the cache. The function should return an object mapping each input module's identifier to its compiled output.
Edge Cases:
- An empty list of modules.
- Duplicate modules in the input list (each instance should be treated independently, but if the content is the same, the cache should be hit).
Examples
Example 1:
Input:
modules = [
"export class MyComponent { ngOnInit() {} }",
"export const API_URL = '/api';"
]
Output:
{
"export class MyComponent { ngOnInit() {} }": "compiled: export class MyComponent { ngOnInit() {} }",
"export const API_URL = '/api';": "compiled: export const API_URL = '/api';"
}
Explanation: Both modules are new. They are compiled, and their compiled outputs are stored in the cache. The function returns the compiled versions.
Example 2:
Input:
modules = [
"export class MyComponent { ngOnInit() {} }",
"export const API_URL = '/api';"
]
initialCache = {
"export class MyComponent { ngOnInit() {} }": "compiled: export class MyComponent { ngOnInit() {} }"
}
Output:
{
"export class MyComponent { ngOnInit() {} }": "compiled: export class MyComponent { ngOnInit() {} }",
"export const API_URL = '/api';": "compiled: export const API_URL = '/api';"
}
Explanation:
The first module is found in the initialCache and its compiled output is reused. The second module is new, so it's compiled and added to the cache. The output reflects both the cached and newly compiled module.
Example 3:
Input:
modules = [
"export class MyComponent { ngOnInit() {} }",
"export class MyComponent { ngOnInit() {} }" // Duplicate content
]
Output:
{
"export class MyComponent { ngOnInit() {} }": "compiled: export class MyComponent { ngOnInit() {} }"
}
Explanation: Even though the module appears twice, it's the same content. The first occurrence triggers compilation and caching. The second occurrence hits the cache. The output map will only contain one entry for the unique module content.
Constraints
- The
modulesinput will be an array of strings. Each string represents the source code of an Angular module. - The cache should be an in-memory data structure (e.g.,
Map<string, string>). - The simulation of compilation is very basic:
(source: string) => \compiled: ${source}``. - Performance is a consideration; the cache lookup and compilation should be efficient.
Notes
- Think about how you would represent the "state" of the cache. Is it passed into the function, or managed internally by a class? For this challenge, consider a function that accepts an initial cache and returns the updated cache along with the compiled outputs.
- The "identifier" of a module for caching purposes in this simplified scenario is its entire source code string. In a real-world Angular build, this would involve more complex hashing of files and dependencies.
- Consider how to handle potential errors during compilation (though for this simplified problem, we don't need to implement error handling beyond the basic transformation).
- The goal is to demonstrate the core concept of build caching: identifying unchanged inputs and reusing previous outputs.