| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- /* eslint-disable prefer-promise-reject-errors */
- import path from 'path';
- import sass, { Options as RenderOptions } from 'sass';
- import fs from 'fs-extra';
- export interface CompileScssOptions {
- COMPONENT_SCSS_PATH: string;
- OUTPUT_SEMI_SCSS_PATH: string;
- OUTPUT_SEMI_CSS_PATH: string;
- OUTPUT_SEMI_CSS_MIN_PATH: string;
- COMPONENT_EXTRA_SCSS_PATH?: string;
- useAbsolutePath?: boolean;
- }
- const defaultOptions = {
- COMPONENT_SCSS_PATH: 'tempory/semi-ui/',
- OUTPUT_SEMI_SCSS_PATH: 'tempory/release/semi.scss',
- OUTPUT_SEMI_CSS_PATH: 'tempory/release/css/semi.css',
- OUTPUT_SEMI_CSS_MIN_PATH: 'tempory/release/css/semi-min.css',
- };
- export default class CompileScss {
- options: CompileScssOptions;
- /**
- * @param {object} [options]
- * @param {string} [options.COMPONENT_SCSS_PATH]
- * @param {string} [options.COMPONENT_EXTRA_SCSS_PATH]
- * @param {string} [options.OUTPUT_SEMI_SCSS_PATH]
- * @param {string} [options.OUTPUT_SEMI_CSS_PATH]
- */
- constructor(options = defaultOptions) {
- // console.log(options)
- this.options = options;
- }
- getScssFolderMap(filepath: string) {
- return fs
- .readdir(filepath)
- .then(files => {
- const folderWithScss: string[] = [];
- files.forEach(fileName => {
- const scssFile = path.join(this.options.COMPONENT_SCSS_PATH, fileName, `${fileName}.scss`);
- try {
- const stats = fs.statSync(scssFile);
- if (stats.isFile()) {
- folderWithScss.push(fileName); // Valid file path is pushed
- }
- } catch (error) {
- // console.log(error)
- }
- });
- return folderWithScss;
- })
- .catch(error => {
- console.error(error);
- throw error;
- });
- }
- async generateSemiScss() {
- const componentScssPath = this.options.COMPONENT_SCSS_PATH;
- const outPutSemiScss = this.options.OUTPUT_SEMI_SCSS_PATH;
- const outPutScss = outPutSemiScss.split('semi.scss')[0] + 'scss';
- const folderWithScss = await this.getScssFolderMap(componentScssPath);
- const relativePath = '../semi-foundation'; // When used in the Semi main repository, use relative paths to build to avoid different semi.scss built when different people publish versions
- const absolutePath = componentScssPath; // When used in semi-server, the absolute path is used to build, so that the semiUI path is not located in the same directory structure as the semi.scss built
- let indexScss = '@import "./scss/index.scss";';
- let globalScss = '@import "./scss/global.scss";';
- let semiUIPath = this.options.useAbsolutePath ? absolutePath : relativePath;
- if (this.options.useAbsolutePath) {
- semiUIPath = absolutePath;
- indexScss = `@import "${outPutScss}/index.scss";`;
- globalScss = `@import "${outPutScss}/global.scss";`;
- }
- const componentScss = folderWithScss
- .map(scssFile => `@import "${semiUIPath}/${scssFile}/${scssFile}.scss"`)
- .concat([
- `@import "${semiUIPath}/button/iconButton.scss"`,
- `@import "${semiUIPath}/input/textarea.scss"`,
- ]) // Handle the scss of iconButton/textarea separately
- .join(';\n');
- const fileContent = `${indexScss}\n${globalScss}\n${componentScss}`;
- return fs.outputFile(outPutSemiScss, fileContent);
- }
- rewriteFile(filePath: string) {
- const extraImport = this.options.COMPONENT_EXTRA_SCSS_PATH;
- let fileStr = fs.readFileSync(filePath, 'utf-8');
- if (extraImport) {
- const localImport = `\n@import "${extraImport}";`;
- try {
- const regex = /(@import '.\/variables.scss';?|@import ".\/variables.scss";?)/g;
- const fileSplit = fileStr.split(regex).filter(item => !!item);
- if (fileSplit.length > 1) {
- fileSplit.splice(fileSplit.length - 1, 0, localImport);
- fileStr = fileSplit.join('');
- }
- } catch (error) { }
- }
- return fileStr;
- }
- sassRender(compressed: boolean = false): Promise<boolean> {
- let outPutSemiCSS = this.options.OUTPUT_SEMI_CSS_PATH;
- const semiScssPath = this.options.OUTPUT_SEMI_SCSS_PATH;
- const config: RenderOptions = {
- file: semiScssPath,
- importer: (url: string) => {
- if (url.startsWith('../semi-ui/')) {
- const result = this.rewriteFile(url);
- return { contents: result };
- }
- return { file: url };
- }
- };
- if (compressed) {
- config.outputStyle = 'compressed';
- outPutSemiCSS = this.options.OUTPUT_SEMI_CSS_MIN_PATH;
- }
- return new Promise((reslove, reject) => {
- sass.render(config, function (error, result) {
- if (error) {
- console.log('error: ', error);
- console.log(error.column, error.message);
- reject(false);
- } else {
- fs.outputFile(outPutSemiCSS, result.css)
- .then(res => {
- reslove(true);
- })
- .catch(err => {
- console.log('err: ', err);
- reject(false);
- });
- }
- });
- });
- }
- async compile() {
- await this.generateSemiScss();
- const compileResult = await this.sassRender();
- let compileMinResult = true;
- if (this.options.OUTPUT_SEMI_CSS_MIN_PATH) {
- compileMinResult = await this.sassRender(true);
- }
- return compileResult && compileMinResult;
- }
- }
|