序
上一篇 webpack less 抽取小技巧 中说到,可以进行多主题的引入。此篇咱们就来实现一下如何一次性生成多个文件主题;
webpack 支持多入口
首先webpack是支持多入口的,通过对象的形式进行entry添加
// webpack.config.js (来源于官网 (https://webpack.docschina.org/guides/entry-advanced/#root))
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: process.env.NODE_ENV,
// 多入口配置项
entry: {
home: './home.less',
account: './account.less',
},
output: {
filename: '[name].js',
},
module: {
rules: [
{
test: /\.scss$/,
use: [
// fallback to style-loader in development
process.env.NODE_ENV !== 'production'
? 'style-loader'
: MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
}),
],
};
如何生成多入口文件
一般来说,我们所需要生成主题css的原less(sass 同理)都应该放置在同一个目录下面,这样方便存储与管理;这样我们就有了单对多,多对多,选择性生成的需求;例如:生产环境中,我们需要将所有的theme样式一起生成,而在开发环境,我们只需要对应的theme即可;如下三种需要支持:
- 1、文件夹下的读取 (fse 读取文件夹下的文件)
- 2、命令行支持的动态文件配置 (运行时 process.argv,动态读取参数)
- 3、默认主题的添加
直接给出代码:
// less2css.js
// 基本依赖
const fse = require('fs-extra')
const path = require('path');
// production 同级
const resolveTop = function (dir) {
return path.join(__dirname, '../../..', dir);
};
// 目标主题目录
const TARGET_THEME_LESS_PATH = resolveTop(`./assets/less/theme/`);
// 基础主题名称
const BASE_THEME_LESS_NAME = 'theme';
// 基础主题目录
const BASE_THEME_LESS_PATH = resolveTop(`./assets/less/`);
const getTargetFiles = function (dir) {
const list = [];
// 要搜索的目录;表示是否还搜索其子目录的标记;匹配文件的正则表达式
// const list = require.context(dir, true, /\.less$/);
// fse 获取文件名称
const files = fse.readdirSync(dir);
console.log('getTargetFiles files', files);
files.forEach(fileName => {
if (/\.less$/.test(fileName)) {
// list.push({
// [fileName]: path.join(dir, fileName)
// });
// entryObj[fileName] = path.join(dir, fileName);
list.push(fileName);
}
});
console.log('getTargetFiles list', list);
return list;
};
// 获取输入文件
// example(命令行): webpack --config less2css.js --custom=theme1,theme2,theme3
const getInputFiles = function() {
// 获取输入参数
var arguments = process.argv;
const setting = arguments[4];
if (setting) {
const splitArr = setting.split('=');
if (splitArr[0] === '--custom') {
const list = splitArr[1].split(',');
const files = list.map(i => (i + '.less'))
console.log('getInputFiles files', files);
return files;
}
}
return [];
};
const tarnsFormThemeList = function(list) {
const entryObj = {};
list.forEach(theme => {
entryObj[theme] = path.join(TARGET_THEME_LESS_PATH, /\.less$/.test(theme) ? theme : (theme + '.less'));
});
return entryObj;
};
const getEntryFun = function() {
// 初始化主题位置
const baseEntryObj = {
[BASE_THEME_LESS_NAME]: path.join(BASE_THEME_LESS_PATH, BASE_THEME_LESS_NAME + '.less')
};
try {
// 获取输入参数
const inputThemeFiles = getInputFiles();
// 输入参数优先
if (inputThemeFiles.length) {
return tarnsFormThemeList(inputThemeFiles);
}
// 目标目录下的less文件
const targetLessFiles = getTargetFiles(TARGET_THEME_LESS_PATH);
// 读取文件目录靠后
if (targetLessFiles.length) {
return tarnsFormThemeList(targetLessFiles);
}
// 默认目录在最后生效
return baseEntryObj;
} catch (error) {
console.log('error', error);
// 程序失败,使用默认目录
return baseEntryObj;
}
};
const entryObj = getEntryFun();
const cssConfig = {
// ...
mode: 'production',
entry: entryObj,
// ...
}
被弃用的 require.context
此处不建议使用 require.context,主要原因是这里会报错,具体原因并没有找到,怀疑 require.context 只能在webpack入口索引的文件内部使用,不能直接使用在 config.js (未确认,保持怀疑态度);利用替代方案 node 的fs(fse) 也可以进行文件夹下文件的读取。
网友评论