@quasar/app-webpack
Version:
Quasar Framework App CLI with Webpack
237 lines (192 loc) • 5.61 kB
JavaScript
const parseArgs = require('minimist')
const { relative, dirname, join } = require('node:path')
const fs = require('node:fs')
const fse = require('fs-extra')
const { log, warn } = require('../utils/logger.js')
const argv = parseArgs(process.argv.slice(2), {
alias: {
h: 'help',
f: 'format'
},
boolean: [ 'h' ],
string: [ 'f' ]
})
function showHelp (returnCode) {
console.log(`
Description
Quickly scaffold files.
Usage
$ quasar new <p|page> [-f <js|ts>] <page_file_name>
$ quasar new <l|layout> [-f <js|ts>] <layout_file_name>
$ quasar new <c|component> [-f <js|ts>] <component_file_name>
$ quasar new <b|boot> [-f <js|ts>] <boot_name>
$ quasar new <s|store> [-f <js|ts>] <store_module_name>
$ quasar new ssrmiddleware [-f <js|ts>] <middleware_name>
Examples
# Create src/pages/MyNewPage.vue:
$ quasar new p MyNewPage
# Create src/pages/MyNewPage.vue and src/pages/OtherPage.vue:
$ quasar new p MyNewPage OtherPage
# Create src/layouts/shop/Checkout.vue
$ quasar new layout shop/Checkout.vue
# Create src/layouts/shop/Checkout.vue (forcing TypeScript)
$ quasar new layout -f ts shop/Checkout.vue
# Create a store with TypeScript (-f ts is optional if tsconfig.json is present)
$ quasar new store -f ts myStore
Options
--help, -h Displays this message
--format -f <option> (optional) Use a supported format for the template.
This gets inferred automatically for your project.
Possible overriding values:
* js - JS template
* ts - TS template
`)
process.exit(returnCode)
}
function showError (message) {
console.log()
warn(message)
showHelp(1)
}
if (argv.help) {
showHelp(0)
}
console.log()
if (argv._.length < 2) {
console.log()
warn(`Wrong number of parameters (${ argv._.length }).`)
showHelp(1)
process.exit(1)
}
const { getCtx } = require('../utils/get-ctx.js')
const { appPaths, cacheProxy } = getCtx()
const hasTypescript = cacheProxy.getModule('hasTypescript')
if (!argv.format) {
argv.format = argv.f = hasTypescript ? 'ts' : 'js'
}
/** @type {string[]} */
const [ rawType, ...names ] = argv._
/** @type {{ format: 'js'|'ts'}} */
const { format } = argv
const typeAliasMap = {
p: 'page',
l: 'layout',
c: 'component',
s: 'store',
b: 'boot'
}
const validAssetTypes = [ ...Object.entries(typeAliasMap).flat(), 'ssrmiddleware' ]
if (validAssetTypes.includes(rawType) === false) {
showError(`Invalid asset type: ${ rawType } (valid values: ${ validAssetTypes.join('|') })`)
}
/** @type {'page'|'layout'|'component'|'store'|'boot'|'ssrmiddleware'} */
const type = typeAliasMap[ rawType ] || rawType
if ([ 'js', 'ts' ].includes(format) === false) {
showError(`Invalid asset format: ${ format } (valid values: js|ts)`)
}
function createFile ({ targetFile, ext, reference }) {
const assetRelativePath = relative(appPaths.appDir, targetFile)
if (fs.existsSync(targetFile)) {
warn(`${ assetRelativePath } already exists.`, 'SKIPPED')
console.log()
return
}
fse.ensureDir(dirname(targetFile))
const templatePath = join('templates/app', format, `${ type }.${ ext }`)
fse.copy(
appPaths.resolve.cli(templatePath),
targetFile,
err => {
if (err) {
console.warn(err)
warn(`Could not generate ${ assetRelativePath }.`, 'FAIL')
return
}
log(`Generated ${ type }: ${ assetRelativePath }`)
if (reference) {
log(`Make sure to reference it in ${ reference }`)
}
log()
}
)
}
async function getAsset (type) {
if (type === 'page') {
return {
relativePath: 'src/pages',
ext: 'vue',
reference: `src/router/routes.${ format }`
}
}
if (type === 'component') {
return {
relativePath: 'src/components',
ext: 'vue'
}
}
if (type === 'boot') {
return {
relativePath: 'src/boot',
ext: format,
reference: 'quasar.config file > boot'
}
}
if (type === 'ssrmiddleware') {
return {
relativePath: 'src-ssr/middlewares',
ext: format,
reference: 'quasar.config file > ssr > middlewares'
}
}
if (type === 'layout') {
return {
relativePath: 'src/layouts',
ext: 'vue',
reference: `src/router/routes.${ format }`
}
}
if (type === 'store') {
const storeProvider = await cacheProxy.getModule('storeProvider')
const relativePath = `src/${ storeProvider.pathKey }`
const targetFolder = appPaths.resolve.app(relativePath)
if (!storeProvider.isInstalled) {
await storeProvider.install()
}
if (fs.existsSync(targetFolder) === false) {
fse.ensureDir(targetFolder)
try {
fse.copySync(
appPaths.resolve.cli(`templates/store/${ storeProvider.name }/${ format }`),
targetFolder
)
}
catch (err) {
console.warn(err)
warn(`Could not generate ${ relativePath }.`, 'FAIL')
process.exit(1)
}
log(`Generated ${ relativePath }`)
}
return {
relativePath,
ext: format
}
}
}
async function generate () {
const { relativePath, ext, reference } = await getAsset(type)
const fullExt = `.${ ext }`
names.forEach(name => {
const file = join(
relativePath,
name + (name.endsWith(fullExt) ? '' : fullExt)
)
const targetFile = appPaths.resolve.app(file)
createFile({
targetFile,
ext,
reference
})
})
}
generate()