vite-plugin-conditional-compile.ts 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import type { FilterPattern, Plugin, ResolvedConfig } from 'vite'
  2. import MagicString from 'magic-string'
  3. import { createFilter } from 'vite'
  4. interface Options {
  5. /**
  6. * @default ["**\/*"]
  7. */
  8. include: FilterPattern
  9. /**
  10. * @default []
  11. */
  12. exclude: FilterPattern
  13. }
  14. type UserOptions = Partial<Options>
  15. type ResolvedOptions = Options
  16. let config: ResolvedConfig = undefined!
  17. const replaceMatched = (code: string, id: string) => {
  18. const env = config.env
  19. const source = new MagicString(code, {
  20. filename: id,
  21. })
  22. source.replace(
  23. /^.*?#if(n?)def\s*(\S+).*[\r\n]{1,2}([\s\S]+?)\s*.*?#endif.*?$/gm,
  24. /**
  25. * 条件替换
  26. * @param _ 匹配的字符串
  27. * @param $1 是否为 not 模式
  28. * @param $2 条件
  29. * @param $3 code
  30. */
  31. (_, $1, $2, $3) => {
  32. const isNot = !!$1
  33. const isKeep = $2.split('||').some((v: string) => {
  34. let flag = false
  35. const [key, value] = v.split('=')
  36. if (value === undefined)
  37. flag = !!env[key]
  38. else
  39. flag = String(env[key]) === value
  40. flag = isNot ? !flag : flag
  41. return flag
  42. })
  43. return isKeep ? $3 : ''
  44. },
  45. )
  46. if (source.hasChanged()) {
  47. return {
  48. code: source.toString(),
  49. map: source.generateMap({
  50. source: id,
  51. file: `${id}.map`,
  52. includeContent: true,
  53. }),
  54. }
  55. }
  56. }
  57. const resolveOptions = (userOptions: UserOptions): ResolvedOptions => {
  58. return {
  59. include: ['**/*'],
  60. exclude: [],
  61. ...userOptions,
  62. }
  63. }
  64. const VitePluginConditionalCompile = (
  65. userOptions: UserOptions = {},
  66. ): Plugin => {
  67. const options = resolveOptions(userOptions)
  68. return {
  69. name: 'vite-plugin-conditional-compile',
  70. enforce: 'pre',
  71. configResolved(_config) {
  72. config = _config
  73. },
  74. transform(code, id) {
  75. const filter = createFilter(options.include, options.exclude)
  76. if (filter(id))
  77. return replaceMatched(code, id)
  78. },
  79. }
  80. }
  81. export default VitePluginConditionalCompile