Skip to content

Commit

Permalink
feat!(app-vite): auto generate base tsconfig and types (#17549)
Browse files Browse the repository at this point in the history
* feat(app-vite): generate .quasar/tsconfig.json

* feat(app-vite): generate tsconfig exclude

* feat(app-vite): add Capacitor dependencies to tsconfig paths
the Vite aliases were already there, thanks to this, TypeScript won't
complain about using Capacitor deps inside src/ anymore

* feat(app-vite): handle folder module and file aliases in tsconfig paths

* refactor(app-vite): extract tsconfig generation to a function

* feat(app-vite): generate nested path aliases for capacitor deps too
e.g. `@capacitor/dep/deep/import`

* feat(app-vite): add build.typescript.extendTsConfig hook

* feat(app-vite): create a better tsconfig, drop presets
enforce TS >=5.4 to use module: 'preserve'
forceConsistentCasingInFileNames defaults to true since TS 5.0
verbatimModuleSyntax will require user to update their codes
jsx: preserve is no longer needed for Vue Language Tools

strict: true and some of the other strict options will be added through a flag

* feat(app-vite): add an option to generate tsconfig with strict rules

compared to previous regular preset:
noUnusedLocals is turned off as it produces extra noise when using ESLint, where the behavior is better as it's configurable

compared to previous stricter config:
noPropertyAccessFromIndexSignature is removed as it doesn't even allow process.env.DEV unless it's augmented explicitly, which we don't do at the moment. It enforces process.env['DEV'] instead, which is annoying and confusing to use. We can't augment the env variables as Node types enforce string, but our own types are actual boolean values.

noImplicitReturns reduces the DX and is not that beneficial in app code compared to its use in library code. It still has it's uses, but it doesn't belong the usual strictness.

* feat(app-vite): only generate .quasar/tsconfig.json if the app has TS

* fix(app-vite): correctly handle non-existent aliases
they were throwing errors, now we skip them for an even slimmer result

* feat(create-quasar): adapt ts-vite-2  to latest specs

* fix(app-vite): suppress the esbuild tsconfig.json warning
when .quasar/tsconfig.json is missing prior to generation

* feat(app-vite): split types generation, handle it on diff
now it will re-generate the types if build.typescript or build.alias gets updated

* feat(app-vite): add prepare command
to generate tsconfig and types

* feat(create-quasar): add postinstall script to run quasar prepare

* feat(create-quasar): remove tsconfig.vue-tsc.json as it's not required anymore

* feat(app-vite): move feature flags into .quasar

* feat(create-quasar): remove unused store-flag.d.ts
as feature flags are handled into .quasar now

* docs(app-vite): document tsconfig changes

* feat(app-vite): generate declarations and vue shims

* feat(app-vite): make vue shim generation optional

* feat(create-quasar): adapt to latest TS specs

* docs(app-vite): document dts generation and feature flag changes

* docs(app-vite): correctly reference .quasar/tsconfig

* docs(app-vite): mention Capacitor TS changes

* refactor(app-vite): queue generateTypes call instead of awaiting

* docs(app-vite): enrich TS-related info in upgrade guide

* Update bex-devserver.js

* Update app-devserver.js

* Update mode.js

* feat(app-vite): generate and utilize tsconfig for JS projects too

Co-authored-by: Razvan Stoenescu <[email protected]>

---------

Co-authored-by: Razvan Stoenescu <[email protected]>
  • Loading branch information
yusufkandemir and rstoenescu authored Nov 14, 2024
1 parent 2b3bc97 commit 76dc721
Show file tree
Hide file tree
Showing 38 changed files with 539 additions and 329 deletions.
2 changes: 2 additions & 0 deletions app-vite/bin/quasar.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import '../lib/node-version-check.js'
const commands = [
'dev',
'build',
'prepare',
'clean',
'inspect',
'describe',
Expand All @@ -23,6 +24,7 @@ if (cmd) {
const mapToCmd = {
d: 'dev',
b: 'build',
p: 'prepare',
e: 'ext',
r: 'run',
c: 'clean',
Expand Down
10 changes: 10 additions & 0 deletions app-vite/lib/app-devserver.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { AppTool } from './app-tool.js'
import { printDevRunningBanner } from './utils/banner.js'
import { encodeForDiff } from './utils/encode-for-diff.js'
import { EntryFilesGenerator } from './entry-files-generator.js'
import { generateTypes } from './types-generator.js'

function getConfSnapshot (extractFn, quasarConf, diffExtractFnMap) {
return extractFn(quasarConf, diffExtractFnMap).map(item => (item ? encodeForDiff(item) : ''))
Expand Down Expand Up @@ -36,6 +37,11 @@ export class AppDevserver extends AppTool {
quasarConf.ssr.manualPostHydrationTrigger
]))

this.registerDiff('types', quasarConf => ([
quasarConf.build.typescript,
quasarConf.build.alias
]))

this.registerDiff('viteUrl', quasarConf => ([
quasarConf.metaConf.APP_URL
]))
Expand Down Expand Up @@ -63,6 +69,10 @@ export class AppDevserver extends AppTool {
this.#entryFiles.generate(quasarConf)
}

if (this.#diff('types', quasarConf)) {
this.#queue(this.#runId, quasarConf, () => generateTypes(quasarConf))
}

if (__isRetry !== true) {
this.#runId++
}
Expand Down
6 changes: 3 additions & 3 deletions app-vite/lib/cmd/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,6 @@ await quasarConfFile.init()

const quasarConf = await quasarConfFile.read()

const { ensureTypesFeatureFlags } = await import('../utils/types-feature-flags.js')
ensureTypesFeatureFlags(quasarConf)

const { QuasarModeBuilder } = await import(`../modes/${ argv.mode }/${ argv.mode }-builder.js`)
const appBuilder = new QuasarModeBuilder({ argv, quasarConf })

Expand All @@ -151,6 +148,9 @@ const { EntryFilesGenerator } = await import('../entry-files-generator.js')
const entryFiles = new EntryFilesGenerator(ctx)
entryFiles.generate(quasarConf)

const { generateTypes } = await import('../types-generator.js')
await generateTypes(quasarConf)

if (typeof quasarConf.build.beforeBuild === 'function') {
await quasarConf.build.beforeBuild({ quasarConf })
}
Expand Down
3 changes: 0 additions & 3 deletions app-vite/lib/cmd/dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,6 @@ await quasarConfFile.init()

const quasarConf = await quasarConfFile.read()

import { ensureTypesFeatureFlags } from '../utils/types-feature-flags.js'
ensureTypesFeatureFlags(quasarConf)

if (quasarConf.metaConf.vueDevtools !== false) {
await startVueDevtools(ctx, quasarConf.metaConf.vueDevtools.port)
}
Expand Down
1 change: 1 addition & 0 deletions app-vite/lib/cmd/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ console.log(`
Commands
dev, d Start a dev server for your App
build, b Build your app for production
prepare, p Prepare the app for linting, type-checking, IDE integration, etc.
clean, c Clean dev/build cache, /dist folder & entry points
new, n Quickly scaffold page/layout/component/... vue file
mode, m Add/remove Quasar Modes for your App
Expand Down
18 changes: 17 additions & 1 deletion app-vite/lib/cmd/mode.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ if (argv._.length !== 0 && argv._.length !== 2) {
import { green, gray } from 'kolorist'

import { getCtx } from '../utils/get-ctx.js'
const ctx = getCtx()
import { generateTypes } from '../types-generator.js'

async function run () {
const [ action, mode ] = argv._

const ctx = getCtx({ mode })

if (![ 'add', 'remove' ].includes(action)) {
console.log()
warn(`Unknown action specified (${ action }).`)
Expand Down Expand Up @@ -83,9 +85,23 @@ async function run () {
}

await actionMap[ action ]({ ctx })

// Ensure types are re-generated accordingly
const { QuasarConfigFile } = await import('../quasar-config-file.js')
const quasarConfFile = new QuasarConfigFile({
ctx,
// host and port don't matter for this command
port: 9000,
host: 'localhost'
})
await quasarConfFile.init()
const quasarConf = await quasarConfFile.read()
await generateTypes(quasarConf)
}

async function displayModes () {
const ctx = getCtx()

log('Detecting installed modes...')

const info = []
Expand Down
62 changes: 62 additions & 0 deletions app-vite/lib/cmd/prepare.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import parseArgs from 'minimist'

import { log } from '../utils/logger.js'

const argv = parseArgs(process.argv.slice(2), {
alias: {
h: 'help'
},
boolean: [ 'h' ]
})

if (argv.help) {
console.log(`
Description
Prepare the app for linting, type-checking, IDE integration, etc.
It will generate the relevant files such as '.quasar/tsconfig.json', types files, etc.
Running 'quasar dev' or 'quasar build' will automatically handle this for you.
Use this command for a lightweight alternative to dev/build. Useful in CI/CD pipelines.
Usage
$ quasar prepare
Options
--help, -h Displays this message
`)
process.exit(0)
}

const { readFileSync } = await import('node:fs')

console.log(
readFileSync(
new URL('../../assets/logo.art', import.meta.url),
'utf8'
)
)

const { getCtx } = await import('../utils/get-ctx.js')
// ctx doesn't matter for this command
const ctx = getCtx({
mode: 'spa',
debug: false,
prod: true
})

const { QuasarConfigFile } = await import('../quasar-config-file.js')
const quasarConfFile = new QuasarConfigFile({
ctx,
// host and port don't matter for this command
port: 9000,
host: 'localhost'
})

await quasarConfFile.init()

const quasarConf = await quasarConfFile.read()

const { generateTypes } = await import('../types-generator.js')
await generateTypes(quasarConf)

log('Generated tsconfig.json and types files in .quasar directory')
log('The app is now prepared for linting, type-checking, IDE integration, etc.')
2 changes: 0 additions & 2 deletions app-vite/lib/modes/bex/bex-installation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import fs from 'node:fs'
import fse from 'fs-extra'

import { log, warn } from '../../utils/logger.js'
import { generateTypesFeatureFlag } from '../../utils/types-feature-flags.js'

export function isModeInstalled (appPaths) {
return fs.existsSync(appPaths.bexDir)
Expand All @@ -23,7 +22,6 @@ export async function addMode ({
log('Creating Browser Extension source folder...')

fse.copySync(appPaths.resolve.cli('templates/bex/common'), appPaths.bexDir)
generateTypesFeatureFlag('bex', appPaths)

const hasTypescript = await cacheProxy.getModule('hasTypescript')
const format = hasTypescript ? 'ts' : 'default'
Expand Down
3 changes: 0 additions & 3 deletions app-vite/lib/modes/electron/electron-installation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import fs from 'node:fs'
import fse from 'fs-extra'

import { log, warn } from '../../utils/logger.js'
import { generateTypesFeatureFlag } from '../../utils/types-feature-flags.js'

const electronDeps = {
electron: 'latest'
Expand Down Expand Up @@ -37,8 +36,6 @@ export async function addMode ({
appPaths.electronDir
)

generateTypesFeatureFlag('electron', appPaths)

log('Creating Electron icons folder...')
fse.copySync(
appPaths.resolve.cli('templates/electron/icons'),
Expand Down
3 changes: 0 additions & 3 deletions app-vite/lib/modes/pwa/pwa-installation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import fs from 'node:fs'
import fse from 'fs-extra'

import { log, warn } from '../../utils/logger.js'
import { generateTypesFeatureFlag } from '../../utils/types-feature-flags.js'

const defaultVersion = '^7.0.0'

Expand Down Expand Up @@ -58,8 +57,6 @@ export async function addMode ({
hasEslint === true ? { filter: src => !src.endsWith('/.eslintrc.cjs') } : void 0
)

generateTypesFeatureFlag('pwa', appPaths)

log('Copying PWA icons to /public/icons/ (if they are not already there)...')
fse.copySync(
appPaths.resolve.cli('templates/pwa-icons'),
Expand Down
3 changes: 0 additions & 3 deletions app-vite/lib/modes/ssr/ssr-installation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import fs from 'node:fs'
import fse from 'fs-extra'

import { log, warn } from '../../utils/logger.js'
import { generateTypesFeatureFlag } from '../../utils/types-feature-flags.js'

export function isModeInstalled (appPaths) {
return fs.existsSync(appPaths.ssrDir)
Expand All @@ -27,8 +26,6 @@ export async function addMode ({
appPaths.ssrDir
)

generateTypesFeatureFlag('ssr', appPaths)

log('SSR support was added')
}

Expand Down
14 changes: 13 additions & 1 deletion app-vite/lib/quasar-config-file.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,14 @@ export class QuasarConfigFile {
plugins: [
quasarEsbuildInjectReplacementsPlugin,
quasarEsbuildVueShimPlugin
]
],
logOverride: {
// .quasar/tsconfig.json won't be available for the first time executing dev/build/prepare.
// So, esbuild will show a warning saying it can't find the `extends` file.
// We need to suppress the warning. Otherwise, it will be noisy and cause a temp file to be created.
// tsconfig is not really important for the config file itself anyway.
'tsconfig.json': 'silent'
}
}
}

Expand Down Expand Up @@ -755,6 +762,11 @@ export class QuasarConfigFile {
assets: appPaths.resolve.src('assets'),
boot: appPaths.resolve.src('boot'),
stores: appPaths.resolve.src('stores')
},

typescript: {
strict: false,
vueShim: false
}
}, cfg.build)

Expand Down
Loading

0 comments on commit 76dc721

Please sign in to comment.