options.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. const fs = require('fs')
  2. const cloneDeep = require('lodash.clonedeep')
  3. const { getRcPath } = require('./util/rcPath')
  4. const { exit } = require('@vue/cli-shared-utils/lib/exit')
  5. const { error } = require('@vue/cli-shared-utils/lib/logger')
  6. const { createSchema, validate } = require('@vue/cli-shared-utils/lib/validate')
  7. const rcPath = exports.rcPath = getRcPath('.vuerc')
  8. const presetSchema = createSchema(joi => joi.object().keys({
  9. bare: joi.boolean(),
  10. useConfigFiles: joi.boolean(),
  11. // TODO: Use warn for router and vuex once @hapi/joi v16 releases
  12. router: joi.boolean(),
  13. routerHistoryMode: joi.boolean(),
  14. vuex: joi.boolean(),
  15. cssPreprocessor: joi.string().only(['sass', 'dart-sass', 'node-sass', 'less', 'stylus']),
  16. plugins: joi.object().required(),
  17. configs: joi.object()
  18. }))
  19. const schema = createSchema(joi => joi.object().keys({
  20. latestVersion: joi.string().regex(/^\d+\.\d+\.\d+(-(alpha|beta|rc)\.\d+)?$/),
  21. lastChecked: joi.date().timestamp(),
  22. packageManager: joi.string().only(['yarn', 'npm', 'pnpm']),
  23. useTaobaoRegistry: joi.boolean(),
  24. presets: joi.object().pattern(/^/, presetSchema)
  25. }))
  26. exports.validatePreset = preset => validate(preset, presetSchema, msg => {
  27. error(`invalid preset options: ${msg}`)
  28. })
  29. exports.defaultPreset = {
  30. useConfigFiles: false,
  31. cssPreprocessor: undefined,
  32. plugins: {
  33. '@vue/cli-plugin-babel': {},
  34. '@vue/cli-plugin-eslint': {
  35. config: 'base',
  36. lintOn: ['save']
  37. }
  38. }
  39. }
  40. exports.defaults = {
  41. lastChecked: undefined,
  42. latestVersion: undefined,
  43. packageManager: undefined,
  44. useTaobaoRegistry: undefined,
  45. presets: {
  46. 'default': exports.defaultPreset
  47. }
  48. }
  49. let cachedOptions
  50. exports.loadOptions = () => {
  51. if (cachedOptions) {
  52. return cachedOptions
  53. }
  54. if (fs.existsSync(rcPath)) {
  55. try {
  56. cachedOptions = JSON.parse(fs.readFileSync(rcPath, 'utf-8'))
  57. } catch (e) {
  58. error(
  59. `Error loading saved preferences: ` +
  60. `~/.vuerc may be corrupted or have syntax errors. ` +
  61. `Please fix/delete it and re-run vue-cli in manual mode.\n` +
  62. `(${e.message})`
  63. )
  64. exit(1)
  65. }
  66. validate(cachedOptions, schema, () => {
  67. error(
  68. `~/.vuerc may be outdated. ` +
  69. `Please delete it and re-run vue-cli in manual mode.`
  70. )
  71. })
  72. return cachedOptions
  73. } else {
  74. return {}
  75. }
  76. }
  77. exports.saveOptions = toSave => {
  78. const options = Object.assign(cloneDeep(exports.loadOptions()), toSave)
  79. for (const key in options) {
  80. if (!(key in exports.defaults)) {
  81. delete options[key]
  82. }
  83. }
  84. cachedOptions = options
  85. try {
  86. fs.writeFileSync(rcPath, JSON.stringify(options, null, 2))
  87. } catch (e) {
  88. error(
  89. `Error saving preferences: ` +
  90. `make sure you have write access to ${rcPath}.\n` +
  91. `(${e.message})`
  92. )
  93. }
  94. }
  95. exports.savePreset = (name, preset) => {
  96. const presets = cloneDeep(exports.loadOptions().presets || {})
  97. presets[name] = preset
  98. exports.saveOptions({ presets })
  99. }