You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
2.6 KiB

4 years ago
  1. const merge = require('merge-source-map')
  2. export interface StylePreprocessor {
  3. render(
  4. source: string,
  5. map: any | null,
  6. options: any
  7. ): StylePreprocessorResults
  8. }
  9. export interface StylePreprocessorResults {
  10. code: string
  11. map?: any
  12. errors: Array<Error>
  13. }
  14. // .scss/.sass processor
  15. const scss: StylePreprocessor = {
  16. render(
  17. source: string,
  18. map: any | null,
  19. options: any
  20. ): StylePreprocessorResults {
  21. const nodeSass = require('sass')
  22. const finalOptions = Object.assign({}, options, {
  23. data: source,
  24. file: options.filename,
  25. outFile: options.filename,
  26. sourceMap: !!map
  27. })
  28. try {
  29. const result = nodeSass.renderSync(finalOptions)
  30. if (map) {
  31. return {
  32. code: result.css.toString(),
  33. map: merge(map, JSON.parse(result.map.toString())),
  34. errors: []
  35. }
  36. }
  37. return { code: result.css.toString(), errors: [] }
  38. } catch (e) {
  39. return { code: '', errors: [e] }
  40. }
  41. }
  42. }
  43. const sass = {
  44. render(
  45. source: string,
  46. map: any | null,
  47. options: any
  48. ): StylePreprocessorResults {
  49. return scss.render(
  50. source,
  51. map,
  52. Object.assign({}, options, { indentedSyntax: true })
  53. )
  54. }
  55. }
  56. // .less
  57. const less = {
  58. render(
  59. source: string,
  60. map: any | null,
  61. options: any
  62. ): StylePreprocessorResults {
  63. const nodeLess = require('less')
  64. let result: any
  65. let error: Error | null = null
  66. nodeLess.render(
  67. source,
  68. Object.assign({}, options, { syncImport: true }),
  69. (err: Error | null, output: any) => {
  70. error = err
  71. result = output
  72. }
  73. )
  74. if (error) return { code: '', errors: [error] }
  75. if (map) {
  76. return {
  77. code: result.css.toString(),
  78. map: merge(map, result.map),
  79. errors: []
  80. }
  81. }
  82. return { code: result.css.toString(), errors: [] }
  83. }
  84. }
  85. // .styl
  86. const styl = {
  87. render(
  88. source: string,
  89. map: any | null,
  90. options: any
  91. ): StylePreprocessorResults {
  92. const nodeStylus = require('stylus')
  93. try {
  94. const ref = nodeStylus(source)
  95. Object.keys(options).forEach(key => ref.set(key, options[key]))
  96. if (map) ref.set('sourcemap', { inline: false, comment: false })
  97. const result = ref.render()
  98. if (map) {
  99. return {
  100. code: result,
  101. map: merge(map, ref.sourcemap),
  102. errors: []
  103. }
  104. }
  105. return { code: result, errors: [] }
  106. } catch (e) {
  107. return { code: '', errors: [e] }
  108. }
  109. }
  110. }
  111. export const processors: { [key: string]: StylePreprocessor } = {
  112. less,
  113. sass,
  114. scss,
  115. styl,
  116. stylus: styl
  117. }