Skip to content

@presencelearning/frontend-devtools

Developer tools and scripts for Presence Learning Angular applications.

Terminal window
npm install --save-dev @presencelearning/frontend-devtools

Requires 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.

Generate Angular services with inlined and optimized SVG content for better bundle sizes and type safety.

Terminal window
# Use default paths (./src/assets/svg/*.svg -> ./src/build/svg-inline-ng-plugin.service.ts)
pl-generate-svg
# Custom paths
pl-generate-svg "./src/assets/icons/*.svg" "./src/services/icons.service.ts"
import { generateSvgService } from '@presencelearning/frontend-devtools/svg';
// Resolves to the number of SVGs processed
const 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.

  • 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
{
"scripts": {
"svg": "pl-generate-svg"
}
}

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',
],
};
// The generated service
@Injectable({ providedIn: 'root' })
export class SvgInlineNgPluginService {
svgs: Record<string, { html: string }> = {
'icon-name': { html: `<svg>...</svg>` },
};
}
// In your component
import { 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 || '';
}
}

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.

Terminal window
# Extract from default ./dist to ./sourcemaps
npx pl-extract-sourcemaps
# Custom dist path (searches recursively)
npx pl-extract-sourcemaps ./dist/my-app
# Custom dist and output paths
npx pl-extract-sourcemaps ./dist ./maps
{
"scripts": {
"build:production": "ng build --configuration production",
"postbuild:production": "pl-extract-sourcemaps"
}
}
import { extractSourcemaps } from '@presencelearning/frontend-devtools/sourcemaps';
// Resolves to the number of files moved
const count = await extractSourcemaps({
distPath: './dist',
outputPath: './sourcemaps',
});

The options type is exported as ExtractSourcemapsOptions.

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.

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.


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

Have a common dev tool pattern that could be shared across projects? Contributions welcome.


Source: packages/devtools