UNPKG

new-themes-switch

Version:

Toolset for switch multiple themes in application based on webpack

378 lines (308 loc) 15 kB
"use strict"; function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var path = require('path'); var fs = require('fs-extra'); var webpack = require('webpack'); var sast = require('sast'); var EntryPlugin = require('webpack/lib/SingleEntryPlugin'); var MiniCssExtractPlugin = require('mini-css-extract-plugin'); var MiniCssExtractPluginOptions = require('mini-css-extract-plugin/dist/plugin-options.json'); var HtmlWebpackPlugin = require('html-webpack-plugin'); var _require = require('./utils'), collectFiles = _require.collectFiles, randomNum = _require.randomNum, recursiveIssuer = _require.recursiveIssuer, clearRules = _require.clearRules; var DEFAULT_INGORED_LIST = ['.DS_Store', '.git']; var TEMP_DIR = path.resolve(process.cwd(), 'temp'); var TEMP_THEMES_DIR_NAME = 'themes'; var TEMP_THEMES_DIR = path.resolve(TEMP_DIR, TEMP_THEMES_DIR_NAME); var DEFAULT_STYLE_NAME = 'default'; var pluginInfo = { name: 'ThemesGeneratorPlugin' }; var DEFAULT_THEME_OUTPUT_DIR = 'static/theme/'; var DEFAULT_CSS_OUTPUT_NAME = '[name]-[contenthash].css'; var ThemesGeneratorPlugin = /*#__PURE__*/function () { function ThemesGeneratorPlugin(options) { _classCallCheck(this, ThemesGeneratorPlugin); this.options = options; } _createClass(ThemesGeneratorPlugin, [{ key: "apply", value: function apply(compiler) { var _this = this; var _this$options = this.options, _this$options$clearTe = _this$options.clearTemp, clearTemp = _this$options$clearTe === void 0 ? true : _this$options$clearTe, disable = _this$options.disable, srcDir = _this$options.srcDir, themesDir = _this$options.themesDir, outputDir = _this$options.outputDir; if (disable) { return; } if (!srcDir) { console.log('srcDir can not be empty'); return; } if (!themesDir) { console.log('themesDir can not be empty'); return; } if (!outputDir) { console.log('outputDir can not be empty'); return; } var themeList = this.getThemeList(); var webpackNewVer = ('hooks' in compiler); var onEntryOption = function onEntryOption(context) { if (_typeof(compiler.options.entry) !== 'object') { console.log('Entry must be an object if ThemesGeneratorPlugin was used!'); return; } console.log('Themes generating started...'); var finalThemes = {}; var publicPath = compiler.options.output && compiler.options.output.publicPath ? compiler.options.output.publicPath : ''; if (themeList && themeList.length > 0) { if (!compiler.options.optimization) { compiler.options.optimization = {}; } if (!compiler.options.optimization.splitChunks) { compiler.options.optimization.splitChunks = {}; } if (!compiler.options.optimization.splitChunks.cacheGroups) { compiler.options.optimization.splitChunks.cacheGroups = {}; } themeList.forEach(function (theme) { var entryPlugin = new EntryPlugin(_this.context || context, theme.path, theme.key); if (webpackNewVer) { entryPlugin.apply(compiler); } else { compiler.apply(entryPlugin); } compiler.options.optimization.splitChunks.cacheGroups[theme.key] = { test: function test(m, c) { var entry = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : theme.key; return m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry; }, chunks: 'all', enforce: true }; var finalOutputDir = outputDir || DEFAULT_THEME_OUTPUT_DIR; finalOutputDir = finalOutputDir.endsWith('/') ? finalOutputDir : "".concat(finalOutputDir, "/"); finalThemes[theme.key] = publicPath ? "".concat(publicPath).concat(publicPath.endsWith('/') ? '' : '/').concat(finalOutputDir).concat(theme.outputName) : "".concat(finalOutputDir).concat(theme.outputName); }); } var definePlugin = new webpack.DefinePlugin({ process: { themes: JSON.stringify(finalThemes) } }); if (webpackNewVer) { definePlugin.apply(compiler); } else { compiler.apply(definePlugin); } var orgMiniCssExtractPlugin; var orgFilename; if (compiler.options.plugins && compiler.options.plugins.length > 0) { compiler.options.plugins.forEach(function (plugin) { if (plugin instanceof MiniCssExtractPlugin) { orgMiniCssExtractPlugin = plugin; } }); } var isMiniCssOldVer = typeof MiniCssExtractPluginOptions.properties.moduleFilename !== 'undefined'; var filenameField = isMiniCssOldVer ? 'moduleFilename' : 'filename'; if (orgMiniCssExtractPlugin) { orgFilename = orgMiniCssExtractPlugin.options[filenameField]; } var moduleFilenameFunc = function moduleFilenameFunc(pathData) { var name = isMiniCssOldVer ? pathData.name : pathData.chunk.name; if (finalThemes[name]) { return "".concat(finalThemes[name]); } var fileName = DEFAULT_CSS_OUTPUT_NAME; if (orgMiniCssExtractPlugin && orgFilename) { if (typeof orgFilename !== 'function') { fileName = orgFilename; } else { fileName = orgFilename(pathData); } } return fileName; }; if (orgMiniCssExtractPlugin) { orgMiniCssExtractPlugin.options[filenameField] = moduleFilenameFunc; } else { var miniCssExtractPlugin = new MiniCssExtractPlugin(_defineProperty({}, filenameField, moduleFilenameFunc)); if (webpackNewVer) { miniCssExtractPlugin.apply(compiler); } else { compiler.apply(miniCssExtractPlugin); } } if (compiler.options.plugins && compiler.options.plugins.length > 0) { var excludeThemeChunks = themeList.map(function (theme) { return theme.key; }); compiler.options.plugins.forEach(function (plugin) { if (plugin instanceof HtmlWebpackPlugin) { if (plugin.options.excludeChunks) { plugin.options.excludeChunks = [].concat(_toConsumableArray(excludeThemeChunks), _toConsumableArray(plugin.options.excludeChunks)); } else { plugin.options.excludeChunks = excludeThemeChunks; } } }); } }; var onEmit = function onEmit(compilation, callback) { var stats = compilation.getStats().toJson(); if (themeList && themeList.length > 0) { themeList.forEach(function (theme) { var outputByThemes = stats.assetsByChunkName[theme.key]; if (outputByThemes) { var pattern = new RegExp("^".concat(theme.key, "(.*).(js|css)")); if (Array.isArray(outputByThemes)) { outputByThemes.forEach(function (fileName) { if (pattern.test(fileName) && compilation.assets[fileName]) { delete compilation.assets[fileName]; } }); } else if (typeof outputByThemes === 'string') { if (pattern.test(outputByThemes) && compilation.assets[outputByThemes]) { delete compilation.assets[outputByThemes]; } } } }); } if (callback && typeof callback === 'function') { callback(); } }; var onDone = function onDone() { fs.removeSync(TEMP_DIR); }; if (webpackNewVer) { compiler.hooks.entryOption.tap(pluginInfo, onEntryOption); compiler.hooks.emit.tapAsync(pluginInfo, onEmit); if (clearTemp) { compiler.hooks.done.tap(pluginInfo, onDone); } } else { compiler.plugin('entry-option', onEntryOption); compiler.plugin('emit', onEmit); if (clearTemp) { compiler.plugin('done', onDone); } } } }, { key: "getThemeList", value: function getThemeList() { var useStaticThemeName = this.options.useStaticThemeName; var themeFileNames = this.generateThemes(); var themeList = []; themeFileNames.forEach(function (fileName) { var index = fileName.lastIndexOf('.'); var key = index > -1 ? fileName.substr(0, index) : fileName; themeList.push({ key: "theme-".concat(key), path: path.resolve(TEMP_THEMES_DIR, fileName), outputName: useStaticThemeName ? "theme-".concat(key, ".css") : "theme-".concat(key, "-").concat(randomNum(10000000, 99999999), ".css") }); }); return themeList; } }, { key: "generateThemes", value: function generateThemes() { var _this$options2 = this.options, srcDir = _this$options2.srcDir, themesDir = _this$options2.themesDir, defaultStyleName = _this$options2.defaultStyleName, _this$options2$ignore = _this$options2.ignoredFilesInThemesDir, ignoredFilesInThemesDir = _this$options2$ignore === void 0 ? [] : _this$options2$ignore, _this$options2$usePur = _this$options2.usePureCSS, usePureCSS = _this$options2$usePur === void 0 ? false : _this$options2$usePur; var ignoredList = DEFAULT_INGORED_LIST.concat(ignoredFilesInThemesDir); fs.removeSync(TEMP_DIR); var orgFiles = fs.readdirSync(themesDir); if (!orgFiles || orgFiles.length === 0) { console.warn('No themes'); return; } fs.ensureDirSync(TEMP_THEMES_DIR); var themesDependencies = []; var defaultStyle = defaultStyleName || DEFAULT_STYLE_NAME; var importPattern = new RegExp("@import (.+)".concat(defaultStyle, "(.+)")); if (usePureCSS) { var _themeFileNames = []; orgFiles.forEach(function (file) { if (defaultStyle !== file && ignoredList.indexOf(file) < 0) { _themeFileNames.push(file); var fileContent = fs.readFileSync(path.join(themesDir, file)).toString(); fs.writeFileSync(path.join(TEMP_THEMES_DIR, file), fileContent); } }); return _themeFileNames; } collectFiles(srcDir, themesDependencies, function (file) { var fileContent = fs.readFileSync(file).toString(); return importPattern.test(fileContent); }); if (themesDependencies.length < 1) { return []; } var importContent = ''; themesDependencies.forEach(function (d) { var newFile = path.join(TEMP_THEMES_DIR, d); fs.ensureFileSync(newFile); fs.copyFileSync(path.join(process.cwd(), d), newFile); var fileContent = fs.readFileSync(newFile).toString(); var astTree = sast.parse(fileContent, { syntax: path.extname(newFile).replace('.', '') }); clearRules(astTree); var newContent = sast.jsonify(astTree).replace(/\$/g, '@'); var finalContent = newContent.replace(importPattern, ''); fs.writeFileSync(newFile, finalContent); importContent += "@import '".concat(path.posix.join('./', d), "';\n"); }); var themeFileNames = []; orgFiles.forEach(function (file) { if (defaultStyle !== file && ignoredList.indexOf(file) < 0) { themeFileNames.push(file); var fileContent = fs.readFileSync(path.join(themesDir, file)).toString(); fs.writeFileSync(path.join(TEMP_THEMES_DIR, file), ThemesGeneratorPlugin.importAfterVariables(file) ? "".concat(fileContent, "\n").concat(importContent) : "".concat(importContent).concat(fileContent)); } }); return themeFileNames; } }], [{ key: "importAfterVariables", value: function importAfterVariables(file) { return file.lastIndexOf('.scss') === file.length - 5 || file.lastIndexOf('.sass') === file.length - 5; } }, { key: "clearTemp", value: function clearTemp() { fs.removeSync(TEMP_DIR); } }]); return ThemesGeneratorPlugin; }(); module.exports = ThemesGeneratorPlugin;