Skip to content

Commit

Permalink
feat: generate a manifest, set PUBLIC_URL, and output a compliant zip (
Browse files Browse the repository at this point in the history
…#36)

* feat: generate a manifest, set PUBLIC_URL, and output a compliant zip

* chore: remove unnecessary duplicate directory removal

* chore: remove test command

* chore: remove superfluous comments

* chore: update local deps in yarn.lock

* chore: remove superfluous manifest, fix author parsing
  • Loading branch information
amcgee committed Sep 10, 2019
1 parent 854f039 commit 243454a
Show file tree
Hide file tree
Showing 12 changed files with 634 additions and 73 deletions.
2 changes: 2 additions & 0 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@dhis2/cli-helpers-engine": "^1.4.2",
"@dhis2/d2-i18n": "^1.0.5",
"@dhis2/ui-core": "^3.9.1",
"archiver": "^3.1.1",
"babel-jest": "^24.9.0",
"chalk": "^2.4.2",
"classnames": "^2.2.6",
Expand All @@ -37,6 +38,7 @@
"jest-cli": "^24.9.0",
"lodash": "^4.17.11",
"moment": "^2.24.0",
"parse-author": "^2.0.0",
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
Expand Down
37 changes: 33 additions & 4 deletions cli/src/commands/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ const { reporter } = require('@dhis2/cli-helpers-engine')

const fs = require('fs-extra')
const chalk = require('chalk')
const path = require('path')

const i18n = require('../lib/i18n')
const compile = require('../lib/compile')
const makePaths = require('../lib/paths')
const makeShell = require('../lib/shell')
const parseConfig = require('../lib/parseConfig')
const exitOnCatch = require('../lib/exitOnCatch')
const generateManifest = require('../lib/generateManifest')
const bundleApp = require('../lib/bundleApp')

const buildModes = ['development', 'production']

Expand All @@ -23,6 +26,14 @@ const getNodeEnv = () => {
return null
}

// This is nasty and frankly wrong (also don't use long unweildy capitalized names in a URL!) but has to match the current DHIS2 app server
// From https://github.com/dhis2/dhis2-core/blob/master/dhis-2/dhis-api/src/main/java/org/hisp/dhis/appmanager/App.java#L360-L371
const getUrlFriendlyName = name =>
name
.trim()
.replace(/[^A-Za-z0-9\s-]/g, '')
.replace(/ /g, '-')

const handler = async ({
cwd,
mode,
Expand All @@ -38,6 +49,12 @@ const handler = async ({
const config = parseConfig(paths)
const shell = makeShell({ config, paths })

process.env.PUBLIC_URL =
process.env.PUBLIC_URL ||
`/api/apps/${getUrlFriendlyName(config.title)}`

await fs.remove(paths.buildOutput)

await exitOnCatch(
async () => {
reporter.info('Generating internationalization strings...')
Expand Down Expand Up @@ -80,10 +97,22 @@ const handler = async ({
process.exit(1)
}

if (fs.pathExistsSync(paths.buildOutput)) {
await fs.remove(paths.buildOutput)
}
await fs.copy(paths.shellBuildOutput, paths.buildOutput)
await fs.copy(paths.shellBuildOutput, paths.buildAppOutput)

reporter.info('Generating manifest...')
await generateManifest(paths, config, process.env.PUBLIC_URL)

const appBundle = paths.buildAppBundle
.replace(/{{name}}/, config.name)
.replace(/{{version}}/, config.version)
reporter.info(
`Creating app archive at ${chalk.bold(
path.relative(process.cwd(), appBundle)
)}...`
)
await bundleApp(paths.buildAppOutput, appBundle)

reporter.print(chalk.green('\n**** DONE! ****'))
}
}

Expand Down
37 changes: 37 additions & 0 deletions cli/src/lib/bundleApp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const fs = require('fs-extra')
const chalk = require('chalk')
const path = require('path')
const archiver = require('archiver')
const { reporter } = require('@dhis2/cli-helpers-engine')

module.exports = (inDir, outFile) => {
return new Promise((resolve, reject) => {
fs.ensureDirSync(path.dirname(outFile))
const output = fs.createWriteStream(outFile)

const archive = archiver('zip', {
zlib: { level: 9 },
})

output.on('close', function() {
reporter.print(chalk.dim(`Total size: ${archive.pointer()} bytes`))
resolve()
})

archive.on('warning', function(err) {
if (err.code === 'ENOENT') {
reporter.warn('[bundler]', err)
} else {
reject(err)
}
})

archive.on('error', function(err) {
reject(err)
})

archive.pipe(output)
archive.directory(inDir, false)
archive.finalize()
})
}
36 changes: 36 additions & 0 deletions cli/src/lib/generateManifest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const { reporter } = require('@dhis2/cli-helpers-engine')
const fs = require('fs-extra')

module.exports = (paths, config, publicUrl) => {
const manifest = {
appType: 'APP',
short_name: config.name,
name: config.title,
description: config.description,
version: config.version,
launch_path: 'index.html',
default_locale: 'en',
activities: {
dhis: {
href: '*',
},
},
icons: {
'48': 'favicon-48x48.png',
},
developer: config.author,

manifest_generated_at: String(new Date()),

display: 'standalone',
theme_color: '#ffffff',
background_color: '#ffffff',
display: 'standalone',

scope: publicUrl,
}

reporter.debug('Generated manifest', manifest)

fs.writeJsonSync(paths.buildAppManifest, manifest, { spaces: 2 })
}
30 changes: 25 additions & 5 deletions cli/src/lib/parseConfig.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
const { reporter } = require('@dhis2/cli-helpers-engine')
const { defaultsDeep, has } = require('lodash')
const { defaultsDeep, has, isPlainObject } = require('lodash')
const fs = require('fs-extra')
const chalk = require('chalk')
const parseAuthorString = require('parse-author')

const requiredConfigFields = {
app: ['name', 'title', 'entryPoints.app'],
lib: ['name', 'entryPoints.lib'],
app: ['name', 'version', 'title', 'entryPoints.app'],
lib: ['name', 'version', 'entryPoints.lib'],
}

const parseAuthor = author => {
if (isPlainObject(author)) {
return {
name: author.name,
email: author.email,
url: author.url,
}
}

if (typeof author === 'string') {
return parseAuthorString(author)
}

return undefined
}

const validateConfig = config => {
Expand All @@ -21,7 +38,7 @@ const validateConfig = config => {
reporter.error(
`Required config field ${chalk.bold(
field
)} not found in d2.config.js`
)} not found in d2.config.js or package.json`
)
process.exit(1)
}
Expand Down Expand Up @@ -51,7 +68,10 @@ const parseConfig = paths => {
config = defaultsDeep(config, require(defaults))

if (fs.existsSync(paths.package)) {
config.name = config.name || require(paths.package).name
const pkg = require(paths.package)
config.name = config.name || pkg.name
config.version = config.version || pkg.version
config.author = config.author || parseAuthor(pkg.author)
}
config.title = config.title || config.name

Expand Down
6 changes: 6 additions & 0 deletions cli/src/lib/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ module.exports = makePaths = (cwd = process.cwd()) => {
shellBuildOutput: path.join(base, './.d2/shell/build'),

buildOutput: path.join(base, './build'),
buildAppOutput: path.join(base, './build/app'),
buildAppManifest: path.join(base, './build/app/manifest.webapp'),
buildAppBundle: path.join(
base,
'./build/bundle/dhis2-{{name}}-{{version}}.zip'
),
}

reporter.debug('PATHS', paths)
Expand Down
1 change: 1 addition & 0 deletions cli/src/lib/shell/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ module.exports = vars => {
...makeShellEnv(vars),
}),
PORT: getShellPort(),
PUBLIC_URL: process.env.PUBLIC_URL,
}

reporter.debug('Env passed to app-shell:', env)
Expand Down
Loading

0 comments on commit 243454a

Please sign in to comment.