feat(deploy): production deployment setup and fixes
- Debian-based api image (bookworm-slim), docker/debian mirrors, prisma binaryTargets for openssl 3.0 - nginx: admin SPA under /admin, TLS via acme.sh (ZeroSSL) + auto-renewal cron, http->https redirect - prisma: add origin_goods.delisted migration, sync missing schema (good_image/tag_font_color/good_tags), fix users.createdAt Timestamptz - api: CORS wildcard reflection, helmet CORP cross-origin, price backfill in persistProductDetail, categoryIcon ancestor fallback, mediaByColor per-color gallery in public goods detail - admin: /admin base path (vite + router) - import-data.mjs: udt_name casting, serial sequence advance fix
This commit is contained in:
+109
-109
@@ -1,109 +1,109 @@
|
||||
# Use Global Properties Sparingly in Plugins
|
||||
|
||||
## Rule
|
||||
|
||||
When using `app.config.globalProperties` in Vue plugins, use them sparingly and with clear naming conventions. Excessive global properties lead to confusion, naming conflicts, and debugging difficulties.
|
||||
|
||||
## Why This Matters
|
||||
|
||||
1. **Implicit dependencies**: Global properties make component dependencies invisible, making code harder to understand and maintain.
|
||||
|
||||
2. **Naming collisions**: Multiple plugins may try to use the same property name (e.g., `$http`, `$api`), causing silent overwrites.
|
||||
|
||||
3. **Debugging difficulty**: When issues arise, tracing back to which plugin provides a global property is challenging.
|
||||
|
||||
4. **IDE limitations**: Global properties may not have proper autocomplete or type checking without careful configuration.
|
||||
|
||||
5. **Testing complexity**: Global state is harder to mock and isolate in unit tests.
|
||||
|
||||
## Bad Practice
|
||||
|
||||
```typescript
|
||||
// Too many global properties from various plugins
|
||||
app.config.globalProperties.$http = axios
|
||||
app.config.globalProperties.$api = apiClient
|
||||
app.config.globalProperties.$auth = authService
|
||||
app.config.globalProperties.$translate = i18n.translate
|
||||
app.config.globalProperties.$format = formatters
|
||||
app.config.globalProperties.$utils = utilities
|
||||
app.config.globalProperties.$config = appConfig
|
||||
app.config.globalProperties.$logger = logger
|
||||
|
||||
// In component - where did all these come from?
|
||||
export default {
|
||||
mounted() {
|
||||
this.$logger.info('Mounted')
|
||||
const data = await this.$http.get(this.$config.apiUrl)
|
||||
this.$api.process(this.$utils.transform(data))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Good Practice
|
||||
|
||||
```typescript
|
||||
// Use provide/inject for most functionality
|
||||
export default {
|
||||
install(app, options) {
|
||||
// Provide services via injection
|
||||
app.provide('api', apiClient)
|
||||
app.provide('auth', authService)
|
||||
app.provide('i18n', i18n)
|
||||
|
||||
// Reserve globalProperties for truly global template helpers
|
||||
// that are used extensively in templates across the app
|
||||
app.config.globalProperties.$t = i18n.translate // Common convention
|
||||
}
|
||||
}
|
||||
|
||||
// In component - explicit dependencies
|
||||
<script setup>
|
||||
import { inject } from 'vue'
|
||||
|
||||
const api = inject('api')
|
||||
const auth = inject('auth')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- $t is acceptable for common template-only usage -->
|
||||
<h1>{{ $t('welcome') }}</h1>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
If you do use globalProperties:
|
||||
|
||||
1. **Use `$` prefix**: This is the Vue convention and avoids conflicts with component data/methods
|
||||
2. **Use unique prefixes for your library**: e.g., `$myLib_translate` for third-party plugins
|
||||
3. **Document all global properties**: Keep a central registry of what each plugin provides
|
||||
|
||||
```typescript
|
||||
// Good: namespaced to avoid conflicts
|
||||
app.config.globalProperties.$myPlugin = {
|
||||
translate: (key) => /* ... */,
|
||||
format: (value) => /* ... */
|
||||
}
|
||||
|
||||
// Usage
|
||||
{{ $myPlugin.translate('key') }}
|
||||
```
|
||||
|
||||
## Auditing Global Properties
|
||||
|
||||
You can inspect all global properties for debugging:
|
||||
|
||||
```typescript
|
||||
console.log(app.config.globalProperties)
|
||||
```
|
||||
|
||||
## When Global Properties Are Acceptable
|
||||
|
||||
1. **Template-only utilities** used very frequently (like `$t` for translations)
|
||||
2. **Legacy migration** when transitioning from Vue 2
|
||||
3. **Libraries that need Options API compatibility** (but prefer also providing inject)
|
||||
|
||||
## References
|
||||
|
||||
- [Vue.js Plugins Documentation](https://vuejs.org/guide/reusability/plugins.html)
|
||||
- [Vue.js Global Properties](https://vuejs.org/api/application.html#app-config-globalproperties)
|
||||
# Use Global Properties Sparingly in Plugins
|
||||
|
||||
## Rule
|
||||
|
||||
When using `app.config.globalProperties` in Vue plugins, use them sparingly and with clear naming conventions. Excessive global properties lead to confusion, naming conflicts, and debugging difficulties.
|
||||
|
||||
## Why This Matters
|
||||
|
||||
1. **Implicit dependencies**: Global properties make component dependencies invisible, making code harder to understand and maintain.
|
||||
|
||||
2. **Naming collisions**: Multiple plugins may try to use the same property name (e.g., `$http`, `$api`), causing silent overwrites.
|
||||
|
||||
3. **Debugging difficulty**: When issues arise, tracing back to which plugin provides a global property is challenging.
|
||||
|
||||
4. **IDE limitations**: Global properties may not have proper autocomplete or type checking without careful configuration.
|
||||
|
||||
5. **Testing complexity**: Global state is harder to mock and isolate in unit tests.
|
||||
|
||||
## Bad Practice
|
||||
|
||||
```typescript
|
||||
// Too many global properties from various plugins
|
||||
app.config.globalProperties.$http = axios
|
||||
app.config.globalProperties.$api = apiClient
|
||||
app.config.globalProperties.$auth = authService
|
||||
app.config.globalProperties.$translate = i18n.translate
|
||||
app.config.globalProperties.$format = formatters
|
||||
app.config.globalProperties.$utils = utilities
|
||||
app.config.globalProperties.$config = appConfig
|
||||
app.config.globalProperties.$logger = logger
|
||||
|
||||
// In component - where did all these come from?
|
||||
export default {
|
||||
mounted() {
|
||||
this.$logger.info('Mounted')
|
||||
const data = await this.$http.get(this.$config.apiUrl)
|
||||
this.$api.process(this.$utils.transform(data))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Good Practice
|
||||
|
||||
```typescript
|
||||
// Use provide/inject for most functionality
|
||||
export default {
|
||||
install(app, options) {
|
||||
// Provide services via injection
|
||||
app.provide('api', apiClient)
|
||||
app.provide('auth', authService)
|
||||
app.provide('i18n', i18n)
|
||||
|
||||
// Reserve globalProperties for truly global template helpers
|
||||
// that are used extensively in templates across the app
|
||||
app.config.globalProperties.$t = i18n.translate // Common convention
|
||||
}
|
||||
}
|
||||
|
||||
// In component - explicit dependencies
|
||||
<script setup>
|
||||
import { inject } from 'vue'
|
||||
|
||||
const api = inject('api')
|
||||
const auth = inject('auth')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- $t is acceptable for common template-only usage -->
|
||||
<h1>{{ $t('welcome') }}</h1>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
If you do use globalProperties:
|
||||
|
||||
1. **Use `$` prefix**: This is the Vue convention and avoids conflicts with component data/methods
|
||||
2. **Use unique prefixes for your library**: e.g., `$myLib_translate` for third-party plugins
|
||||
3. **Document all global properties**: Keep a central registry of what each plugin provides
|
||||
|
||||
```typescript
|
||||
// Good: namespaced to avoid conflicts
|
||||
app.config.globalProperties.$myPlugin = {
|
||||
translate: (key) => /* ... */,
|
||||
format: (value) => /* ... */
|
||||
}
|
||||
|
||||
// Usage
|
||||
{{ $myPlugin.translate('key') }}
|
||||
```
|
||||
|
||||
## Auditing Global Properties
|
||||
|
||||
You can inspect all global properties for debugging:
|
||||
|
||||
```typescript
|
||||
console.log(app.config.globalProperties)
|
||||
```
|
||||
|
||||
## When Global Properties Are Acceptable
|
||||
|
||||
1. **Template-only utilities** used very frequently (like `$t` for translations)
|
||||
2. **Legacy migration** when transitioning from Vue 2
|
||||
3. **Libraries that need Options API compatibility** (but prefer also providing inject)
|
||||
|
||||
## References
|
||||
|
||||
- [Vue.js Plugins Documentation](https://vuejs.org/guide/reusability/plugins.html)
|
||||
- [Vue.js Global Properties](https://vuejs.org/api/application.html#app-config-globalproperties)
|
||||
|
||||
Reference in New Issue
Block a user