Skip to content

Commit

Permalink
fix: jspm inject usability #147 (#151)
Browse files Browse the repository at this point in the history
  • Loading branch information
Aslemammad authored and guybedford committed Apr 8, 2023
1 parent ec06237 commit 4e18e6a
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 26 deletions.
40 changes: 34 additions & 6 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ cli
.option('-p, --provider <proider>', 'the default provider to use for a new install, defaults to `jspm`', { default: 'jspm' })
.option('--force', 'force install even if the import map is up to date', { default: false })
.option('--stdout', 'output the import map to stdout', { default: false })
.option('--preload', 'preload the import map into the browser', { default: false })
.option('--integrity', 'generate integrity hashes for all dependencies', { default: false })
.option('--compact', 'output a compact import map', { default: false })
.help()

Expand All @@ -47,7 +45,10 @@ cli
.action(wrapCommandAndRemoveStack(link))

cli
.command('inject <htmlFile> [...packages]', 'inject the import map into the provided HTML source')
.command('inject <htmlFile>', 'inject the import map into the given HTML file')
.option('-p, --packages <...packages>', 'specific list of packages to extract for injection', { type: [] })
.option('--preload', 'preload the import map into the browser', { default: false })
.option('--integrity', 'generate integrity hashes for all dependencies', { default: false })
.option('-o, --output <outputFile>', '.html file for the output html with the import-map')
.action(wrapCommandAndRemoveStack(inject))

Expand Down Expand Up @@ -78,13 +79,40 @@ function noArgs() {
}
}

['uninstall', 'link', 'inject', 'extract'].forEach(command => cli.on(`command:${command}`, noArgs))
['uninstall', 'link', 'extract'].forEach(command => cli.on(`command:${command}`, noArgs))

// short commands
// short commands and other hacks
switch (process.argv[2]) {
case 'cc':
process.argv[2] = 'clear-cache'
break
case 'inject': {
let pIndex = process.argv.indexOf('-p', 2)
if (pIndex === -1)
pIndex = process.argv.indexOf('--packages', 2)
if (pIndex !== -1) {
const pArgs = process.argv.splice(pIndex)
for (let i = 0; i < pArgs.length; i++) {
if (pArgs[i] === '-p' || pArgs[i] === '--packages')
continue
if (pArgs[i].startsWith('-')) {
console.error(`${c.red('Err:')} --packages flag must be the last flag\n`)
process.exit(1)
}
if (pArgs[i - 1] !== '-p' && pArgs[i - 1] !== '--packages') {
pArgs.splice(i, 0, '-p')
i++
}
}
process.argv.splice(pIndex, pArgs.length, ...pArgs)
}
}
}

cli.parse()
try {
cli.parse()
}
catch (e) {
if (e.constructor.name === 'CACError')
console.error(`${c.red('Err:')} ${e.message}\n`)
}
33 changes: 21 additions & 12 deletions src/inject.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import fs from 'fs/promises'
import { pathToFileURL } from 'node:url'
import c from 'picocolors'
import { Generator } from '@jspm/generator'
import type { Flags } from './types'
import type { InjectFlags } from './types'
import {
JspmError,
cwdUrl,
getEnv,
getInputMap,
Expand All @@ -17,6 +19,7 @@ const defaultHtmlTemplate = `<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>JSPM example</title>
<script type="importmap"></script>
</head>
<body>
</body>
Expand All @@ -34,9 +37,10 @@ const htmlExists = async (htmlFile: string) => {

export default async function inject(
htmlFile: string,
packages: string[],
flags: Flags,
flags: InjectFlags,
): Promise<string> {
const packages = (flags.packages ?? []).filter(x => x)
const pins = packages.length > 0 ? packages : false
const inputMap = await getInputMap(flags)
const env = getEnv(flags, true, inputMap)

Expand All @@ -46,8 +50,8 @@ export default async function inject(
}
startLoading(
`Injecting ${
packages.length ? `${packages.join(', ')} ` : ''
}into ${htmlFile}...`,
Array.isArray(pins) ? `${pins.join(', ')} into` : 'traced import map for'
} ${c.cyan(htmlFile)}...`,
)
const generator = new Generator({
env,
Expand All @@ -56,14 +60,19 @@ export default async function inject(
mapUrl: getInputMapUrl(flags),
resolutions: getResolutions(flags),
})
const trace = packages.length === 0
const html = await fs.readFile(htmlFile, 'utf-8')

let html: string
try {
html = await fs.readFile(htmlFile, 'utf-8')
}
catch (e) {
throw new JspmError(`${c.cyan(htmlFile)} is not an existing file to inject`)
}

const output = await generator.htmlInject(html, {
pins: packages,
trace,
htmlUrl: new URL(htmlFile, `file:///${process.cwd().replace(/\\/g, '/')}`)
.href,
pins,
trace: pins === false,
htmlUrl: new URL(htmlFile, `${pathToFileURL(process.cwd())}/`).href,
comment: false,
preload: flags.preload,
integrity: flags.integrity,
Expand All @@ -77,7 +86,7 @@ export default async function inject(
await fs.writeFile(flags.output ?? htmlFile, output, 'utf-8')

console.warn(
`${c.green('Ok:')} Injected ${flags.output ?? htmlFile}`,
`${c.green('Ok:')} Injected ${c.cyan(flags.output ?? htmlFile)}`,
)

return output
Expand Down
3 changes: 2 additions & 1 deletion src/install.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Generator } from '@jspm/generator'
import c from 'picocolors'
import type { Flags, IImportMapFile } from './types'
import { attachEnv, cwdUrl, getEnv, getInputMap, getInputMapUrl, getProvider, getResolutions, startLoading, stopLoading, writeMap } from './utils'

Expand All @@ -24,7 +25,7 @@ export default async function install(packages: string[], flags: Flags) {
})

startLoading(
`Installing ${resolvedPackages.map(p => p.alias || p.target).join(', ')} (${env.join(', ')})`,
`Installing ${c.bold(resolvedPackages.map(p => p.alias || p.target).join(', '))} (${env.join(', ')})`,
)

if (resolvedPackages.length)
Expand Down
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export interface Flags {
compact?: boolean
}

export type InjectFlags = Flags & {
packages: string[]
}

export type IImportMap = ReturnType<Generator['getMap']>

export type IImportMapFile = IImportMap & { env?: string[]; provider?: string }
8 changes: 4 additions & 4 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function wrapCommandAndRemoveStack(fn: Function) {
stopLoading()
process.exitCode = 1
if (e instanceof JspmError || e?.jspmError) {
console.error(`${c.red('Err:')} ${e.message}`)
console.error(`${c.red('Err:')} ${e.message}\n`)
return
}
throw e
Expand Down Expand Up @@ -48,12 +48,12 @@ export async function writeMap(
const outfile = flags.output || flags.map || 'importmap.json'
if (!outfile.endsWith('.json') && !outfile.endsWith('.importmap')) {
throw new JspmError(
'Extract will only write to ".json" or ".importmap" files. Use "jspm inject" for HTML injection.',
`Extract will only write to ${c.bold('".json"')} or ${c.bold('".importmap"')} files. Use ${c.bold('jspm inject')} for HTML injection.`,
)
}
await fs.writeFile(outfile, output)
!silent && console.warn(
`${c.green('Ok:')} Updated ${outfile}`,
`${c.green('Ok:')} Updated ${c.cyan(outfile)}`,
)
}
}
Expand Down Expand Up @@ -137,7 +137,7 @@ export function getResolutions(flags: Flags): Record<string, string> {
resolutions.map((resolution) => {
if (!resolution.includes('=')) {
throw new JspmError(
'Resolutions must be mappings from aliases to targets, for example of the form "--resolution pkg=x.y.z"',
`Resolutions must be mappings from aliases to targets, for example of the form ${c.bold('--resolution pkg=x.y.z')}`,
)
}
return resolution.split('=')
Expand Down
9 changes: 6 additions & 3 deletions test/inject.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import inject from '../src/inject'

{
/* basic inject */
const map = await inject('test/fixtures/index.html', ['react'], {
const map = await inject('test/fixtures/index.html', {
stdout: true,
map: 'test/importmap.json',
packages: ['react'],
})
assert.ok(
map.includes('"react":'),
Expand All @@ -15,9 +16,10 @@ import inject from '../src/inject'

{
/* output html file */
await inject('test/fixtures/index.html', ['react'], {
await inject('test/fixtures/index.html', {
map: 'test/importmap.json',
output: 'test/fixtures/index.injected.html',
packages: ['react'],
})
const html = await fs.readFile('test/fixtures/index.injected.html', 'utf-8')
assert.ok(
Expand All @@ -32,8 +34,9 @@ import inject from '../src/inject'
}
catch {}

await inject('test/fixtures/index.404.html', ['react'], {
await inject('test/fixtures/index.404.html', {
map: 'test/importmap.json',
packages: ['react'],
})
const html = await fs.readFile('test/fixtures/index.404.html', 'utf-8')
assert.ok(
Expand Down

0 comments on commit 4e18e6a

Please sign in to comment.