diff --git a/.gitignore b/.gitignore index e7fefb849e8764dce178a8651921d4cec77ccb57..2a2a8c8bed6405d9ef3f13aeb8ec722446440c12 100755 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,5 @@ jsconfig.json .history *.log -functions/mock \ No newline at end of file +functions/mock +temp/** diff --git a/.webpackrc.js b/.webpackrc.js index 9886584900e3a383b2a9a1ec8f0cd46fb8c561e6..c198018409d9173c2f8a2b72ec6da3e26c8125dc 100755 --- a/.webpackrc.js +++ b/.webpackrc.js @@ -29,19 +29,18 @@ export default { cssLoaderOptions: { modules: true, getLocalIdent: (context, localIdentName, localName) => { - if (context.resourcePath.includes('node_modules')) { + if ( + context.resourcePath.includes('node_modules') || + context.resourcePath.includes('ant.design.pro.less') + ) { return localName; } - - let antdProPath = context.resourcePath.match(/src(.*)/)[1].replace('.less', ''); - if (context.resourcePath.includes('components')) { - antdProPath = antdProPath.replace('components/', ''); - } + const antdProPath = context.resourcePath.match(/src(.*)/)[1].replace('.less', ''); const arr = antdProPath .split('/') .map(a => a.replace(/([A-Z])/g, '-$1')) .map(a => a.toLowerCase()); - return `antd-pro${arr.join('-')}-${localName}`.replace('--', '-'); + return `antd-pro${arr.join('-')}-${localName}`.replace(/--/g, '-'); }, }, }; diff --git a/scripts/AddlocalIdentName.js b/scripts/AddlocalIdentName.js new file mode 100644 index 0000000000000000000000000000000000000000..8c6a08891c37649898aedcdd7d1cbcf7a6d03bfb --- /dev/null +++ b/scripts/AddlocalIdentName.js @@ -0,0 +1,47 @@ +/* eslint-disable */ +const postcss = require('postcss'); +const syntax = require('postcss-less'); + +const LocalIdentNameplugin = postcss.plugin('LocalIdentNameplugin', ({ localIdentName }) => { + return lessAST => { + // loop add localIdentName + const loop = nodes => { + nodes.forEach(item => { + // Not converted :global + if (item.nodes && item.selector !== ':global') { + loop(item.nodes); + } + // 将global的 节点加到 parents + if (item.selector === ':global') { + const parentNodes = item.parent.nodes; + const childrenNodes = item.nodes; + const index = parentNodes.findIndex(node => { + return node.selector === ':global'; + }); + childrenNodes.unshift(index, 1); + Array.prototype.splice.apply(parentNodes, item.nodes); + item.parent.nodes = parentNodes; + return; + } + // 删除 :global(className) 保留 className + if (item.selector && !item.selector.includes('(')) { + if (item.selector.includes(':global(')) { + // converted :global(.className) + const className = item.selector.match(/:global\((\S*)\)/)[1]; + item.selector = className; + return; + } + const className = item.selector.replace(/\./g, `.${localIdentName}`); + item.selector = className; + } + }); + }; + loop(lessAST.nodes); + }; +}); + +const AddlocalIdentName = (lessPath, lessText, localIdentName) => { + return postcss([LocalIdentNameplugin({ localIdentName })]).process(lessText, { syntax }); +}; + +module.exports = AddlocalIdentName; diff --git a/scripts/getLocalIdentName.js b/scripts/getLocalIdentName.js new file mode 100644 index 0000000000000000000000000000000000000000..aa860c7f96df434f03b34e7f484ec9e72add70bb --- /dev/null +++ b/scripts/getLocalIdentName.js @@ -0,0 +1,8 @@ +module.exports = path => { + const antdProPath = path.match(/src(.*)/)[1].replace('.less', ''); + const arr = antdProPath + .split('/') + .map(a => a.replace(/([A-Z])/g, '-$1')) + .map(a => a.toLowerCase()); + return `antd-pro${arr.join('-')}-`.replace(/--/g, '-'); +}; diff --git a/scripts/mergeLessPlugin.js b/scripts/mergeLessPlugin.js new file mode 100755 index 0000000000000000000000000000000000000000..4b3034b32064a4f39443aa5a606c2218b443d418 --- /dev/null +++ b/scripts/mergeLessPlugin.js @@ -0,0 +1,73 @@ +#!/usr/bin/env node +/** + * 这个方法用来处理 css-modlue + * 由于没有开源插件,所以自己撸了一个 + */ + +const fs = require('fs'); +const path = require('path'); +const getLocalIdentName = require('./getLocalIdentName'); +const AddlocalIdentName = require('./AddlocalIdentName'); +const replacedefaultLess = require('./replacedefaultLess'); +// read less file list +const lessArray = ['@import "../node_modules/antd/lib/style/themes/default.less";']; + +const loopAllLess = parents => { + const paths = fs.readdirSync(parents); + const promiseList = []; + paths.forEach(itemPath => { + if (itemPath === 'style' || itemPath === 'demo') { + return; + } + // file status + const fileStatus = fs.lstatSync(path.join(parents, itemPath)); + // is file + // is Directory + if (fileStatus.isDirectory()) { + return loopAllLess(path.join(parents, itemPath)); + } + // is less file + if (itemPath.indexOf('.less') > -1) { + const relaPath = path.join(parents, itemPath); + // post css add localIdentNameplugin + const fileContent = replacedefaultLess(relaPath); + // push less file + promiseList.push( + AddlocalIdentName(relaPath, fileContent, getLocalIdentName(relaPath)).then(result => { + lessArray.push(result); + }) + ); + } + }); + return Promise.all(promiseList); +}; + +class mergeLessPlugin { + constructor(options) { + const defaulOptions = { + stylesDir: path.join(__dirname, './src/'), + outFile: path.join(__dirname, './tmp/ant.design.pro.less'), + }; + this.options = Object.assign(defaulOptions, options); + this.generated = false; + } + + apply(compiler) { + const { options } = this; + compiler.plugin('emit', (compilation, callback) => { + const { outFile } = options; + // covert less + if (fs.existsSync(outFile)) { + fs.unlinkSync(outFile); + } else { + fs.mkdir(path.dirname(outFile)); + } + loopAllLess(options.stylesDir).then(() => { + fs.writeFileSync(outFile, lessArray.join('\n')); + callback(); + }); + }); + } +} + +module.exports = mergeLessPlugin; diff --git a/scripts/replacedefaultLess.js b/scripts/replacedefaultLess.js new file mode 100644 index 0000000000000000000000000000000000000000..a36a4af39911786b284586d1924415d45a58679d --- /dev/null +++ b/scripts/replacedefaultLess.js @@ -0,0 +1,11 @@ +const fs = require('fs-extra'); + +const replacedefaultLess = lessPath => { + const fileContent = fs.readFileSync(lessPath).toString(); + let lessString = fileContent; + if (lessString.includes("@import '~antd/lib/style/themes/default.less'")) { + lessString = lessString.replace("@import '~antd/lib/style/themes/default.less';", ''); + } + return lessString.replace(/@import '.*\/utils.less';/, ''); +}; +module.exports = replacedefaultLess; diff --git a/webpack.config.js b/webpack.config.js index 85f19db3650d8c0832e62c2a98545efd3cc44e6a..e29a1db5ba8fda431290bef243bf28478211d516 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,19 +1,31 @@ import AntDesignThemePlugin from 'antd-theme-webpack-plugin'; +import MergeLessPlugin from './scripts/mergeLessPlugin'; const path = require('path'); export default webpackConfig => { + // 将所有 less 合并为一个供 themePlugin使用 + const outFile = path.join(__dirname, './temp/ant-design-pro.less'); + const stylesDir = path.join(__dirname, './src/'); + + const mergeLessPlugin = new MergeLessPlugin({ + stylesDir, + outFile, + }); + const options = { antDir: path.join(__dirname, './node_modules/antd'), - stylesDir: path.join(__dirname, './src/'), + stylesDir, varFile: path.join(__dirname, './node_modules/antd/lib/style/themes/default.less'), - mainLessFile: path.join(__dirname, './src/index.less'), + mainLessFile: outFile, themeVariables: ['@primary-color'], indexFileName: 'index.html', }; - const themePlugin = new AntDesignThemePlugin(options); + // in config object + webpackConfig.plugins.push(mergeLessPlugin); webpackConfig.plugins.push(themePlugin); + return webpackConfig; };