@presencelearning/frontend-devtools
Developer tools and scripts for Presence Learning Angular applications.
Installation
Section titled “Installation”npm install --save-dev @presencelearning/frontend-devtoolsRequires Node >=20.0.0. Ships two CLI binaries (pl-generate-svg, pl-extract-sourcemaps) and two subpath exports (./svg, ./sourcemaps). There is no root export — always import from a subpath.
SVG Service Generation
Section titled “SVG Service Generation”Generate Angular services with inlined and optimized SVG content for better bundle sizes and type safety.
CLI Usage
Section titled “CLI Usage”# Use default paths (./src/assets/svg/*.svg -> ./src/build/svg-inline-ng-plugin.service.ts)pl-generate-svg
# Custom pathspl-generate-svg "./src/assets/icons/*.svg" "./src/services/icons.service.ts"Programmatic API
Section titled “Programmatic API”import { generateSvgService } from '@presencelearning/frontend-devtools/svg';
// Resolves to the number of SVGs processedconst count = await generateSvgService({ svgGlob: './src/assets/svg/*.svg', outputFile: './src/build/svg-inline-ng-plugin.service.ts', includeAngularDecorator: true, // default: true svgoConfig: { /* custom SVGO config */ },});The options type is exported as GenerateSvgServiceOptions.
Features
Section titled “Features”- Scans directory for SVG files using glob patterns
- Optimizes SVGs with SVGO
- Generates typed Angular service with
@Injectable - Inlines SVG content for zero runtime loading
- Supports custom SVGO configuration
- Full TypeScript support
NPM Script Integration
Section titled “NPM Script Integration”{ "scripts": { "svg": "pl-generate-svg" }}SVGO Configuration
Section titled “SVGO Configuration”Create a svgo.config.js file in your project root:
module.exports = { multipass: true, plugins: [ { name: 'preset-default', params: { overrides: { inlineStyles: { onlyMatchedOnce: false, }, removeViewBox: false, }, }, }, 'prefixIds', ],};Usage in Angular
Section titled “Usage in Angular”// The generated service@Injectable({ providedIn: 'root' })export class SvgInlineNgPluginService { svgs: Record<string, { html: string }> = { 'icon-name': { html: `<svg>...</svg>` }, };}
// In your componentimport { SvgInlineNgPluginService } from './build/svg-inline-ng-plugin.service';
@Component({ selector: 'app-icon', template: '<div [innerHTML]="getSvg(\'icon-name\')"></div>',})export class IconComponent { constructor(private svgService: SvgInlineNgPluginService) {}
getSvg(name: string) { return this.svgService.svgs[name]?.html || ''; }}Sourcemap Extraction
Section titled “Sourcemap Extraction”Moves .map files out of your build output into a separate directory. Useful for uploading to error monitoring services (Sentry, Rollbar) while keeping them out of production bundles.
This is destructive by design: the source .map files are deleted from dist after being copied, and the output directory is wiped before extraction starts. Point it at a scratch directory, never at something you want to keep.
CLI Usage
Section titled “CLI Usage”# Extract from default ./dist to ./sourcemapsnpx pl-extract-sourcemaps
# Custom dist path (searches recursively)npx pl-extract-sourcemaps ./dist/my-app
# Custom dist and output pathsnpx pl-extract-sourcemaps ./dist ./mapspackage.json Integration
Section titled “package.json Integration”{ "scripts": { "build:production": "ng build --configuration production", "postbuild:production": "pl-extract-sourcemaps" }}Programmatic Usage
Section titled “Programmatic Usage”import { extractSourcemaps } from '@presencelearning/frontend-devtools/sourcemaps';
// Resolves to the number of files movedconst count = await extractSourcemaps({ distPath: './dist', outputPath: './sourcemaps',});The options type is exported as ExtractSourcemapsOptions.
Safety Features
Section titled “Safety Features”validateOutputPath throws before any deletion when:
- The output path is empty or whitespace-only
- The output path is the same as the dist path
- The paths are nested (output inside dist, or vice versa)
- The output path is the current directory
- The output path is on a denylist of system directories —
/,/Users,/home,/var,/usr,/bin,/etc
Note that the last check is a fixed denylist, not a general “is this a system directory” test.
Migration from Project Scripts
Section titled “Migration from Project Scripts”If you have node-scripts/extract-sourcemaps.mjs in your project:
Before:
{ "scripts": { "extract-sourcemaps": "node ./node-scripts/extract-sourcemaps.mjs" }}After:
{ "scripts": { "extract-sourcemaps": "pl-extract-sourcemaps" }}For projects with nested dist directories (like ./dist/therapy-essentials):
{ "scripts": { "extract-sourcemaps": "pl-extract-sourcemaps ./dist/therapy-essentials" }}Then remove your local node-scripts/extract-sourcemaps.mjs file.
Planned Tools
Section titled “Planned Tools”The following tools are planned for future releases:
- Cloudflare Utilities — API helpers for Pages deployments and DNS management
- SSL Certificate Generator — Self-signed certificates for local HTTPS development
Contributing
Section titled “Contributing”Have a common dev tool pattern that could be shared across projects? Contributions welcome.
Source: packages/devtools