UNPKG

3.82 kBPlain TextView Raw
1import * as path from 'path'
2import * as fs from 'fs-extra'
3import * as postcss from 'postcss'
4import * as pxtransform from 'postcss-pxtransform'
5import transformCSS from 'taro-css-to-react-native'
6import {
7 FILE_PROCESSOR_MAP,
8 npm as npmProcess,
9 processTypeEnum,
10 printLog,
11 chalk
12} from '@tarojs/helper'
13
14import { StyleSheetValidation } from './StyleSheet/index'
15
16import * as stylelintConfig from '../config/rn-stylelint.json'
17
18const DEVICE_RATIO = 'deviceRatio'
19
20function getWrapedCSS (css) {
21 return `
22import { StyleSheet, Dimensions } from 'react-native'
23
24// 一般app 只有竖屏模式,所以可以只获取一次 width
25const deviceWidthDp = Dimensions.get('window').width
26const uiWidthPx = 375
27
28function scalePx2dp (uiElementPx) {
29 return uiElementPx * deviceWidthDp / uiWidthPx
30}
31
32export default StyleSheet.create(${css})
33`
34}
35
36/**
37 * @description 读取 css/scss/less 文件,预处理后,返回 css string
38 * @param {string} filePath
39 * @param {object} pluginsConfig
40 * @param {string} appPath
41 * @returns {*}
42 */
43function loadStyle ({ filePath, pluginsConfig }, appPath) {
44 const fileExt = path.extname(filePath)
45 const pluginName = FILE_PROCESSOR_MAP[fileExt]
46 if (pluginName) {
47 return npmProcess
48 .callPlugin(pluginName, null, filePath, pluginsConfig[pluginName] || {}, appPath)
49 .then(item => {
50 return {
51 css: item.css.toString(),
52 filePath
53 }
54 })
55 .catch(e => {
56 printLog(processTypeEnum.ERROR, '样式预处理', filePath)
57 console.log(e.stack)
58 })
59 }
60 return new Promise((resolve, reject) => {
61 fs.readFile(filePath, 'utf-8', (err, content) => {
62 if (err) {
63 return reject(err)
64 }
65 resolve({
66 css: content,
67 filePath
68 })
69 })
70 })
71}
72
73/**
74 * @description 传入 css string ,返回 postCSS 处理后的 css string
75 * @param {string} css
76 * @param {string} filePath
77 * @param {object} projectConfig
78 * @returns {Function | any}
79 */
80function postCSS ({ css, filePath, projectConfig }) {
81 const pxTransformConfig = {
82 designWidth: projectConfig.designWidth || 750
83 }
84 if (projectConfig.hasOwnProperty(DEVICE_RATIO)) {
85 pxTransformConfig[DEVICE_RATIO] = projectConfig.deviceRatio
86 }
87 return postcss([
88 require('stylelint')(stylelintConfig),
89 require('postcss-reporter')({ clearReportedMessages: true }),
90 pxtransform({
91 platform: 'rn',
92 ...pxTransformConfig
93 })
94 ])
95 .process(css, { from: filePath })
96 .then(result => {
97 return {
98 css: result.css,
99 filePath
100 }
101 })
102 .catch(e => {
103 printLog(processTypeEnum.ERROR, '样式转换', filePath)
104 console.log(e.stack)
105 })
106}
107
108function getStyleObject ({ css, filePath }) {
109 let styleObject = {}
110 try {
111 styleObject = transformCSS(css)
112 } catch (err) {
113 printLog(processTypeEnum.WARNING, 'css-to-react-native 报错', filePath)
114 console.log(chalk.red(err.stack))
115 }
116 return styleObject
117}
118
119function validateStyle ({ styleObject, filePath }) {
120 for (const name in styleObject) {
121 try {
122 StyleSheetValidation.validateStyle(name, styleObject)
123 } catch (err) {
124 // 先忽略掉 scalePx2dp 的报错
125 if (/Invalid prop `.*` of type `string` supplied to `.*`, expected `number`[^]*/g.test(err.message)) return
126 printLog(processTypeEnum.WARNING, '样式不支持', filePath)
127 console.log(chalk.red(err.message))
128 }
129 }
130}
131
132function writeStyleFile ({ css, tempFilePath }) {
133 const fileContent = getWrapedCSS(css.replace(/"(scalePx2dp\(.*?\))"/g, '$1'))
134 fs.ensureDirSync(path.dirname(tempFilePath))
135 fs.writeFileSync(tempFilePath, fileContent)
136 printLog(processTypeEnum.GENERATE, '生成样式文件', tempFilePath)
137}
138
139export { loadStyle, postCSS, getStyleObject, validateStyle, writeStyleFile }