|
- import {
- ensureDir,
- readFile,
- readdirSync,
- statSync,
- writeFile
- } from "fs-extra";
- import {TextDecoder} from "util";
- import path from "path";
- import tmp from "tmp";
- import postcss from "postcss";
- import postcssModules from "postcss-modules";
- import less from "less";
- import stylus from "stylus";
- import resolveFile from "resolve-file";
- const defaultOptions = {
- plugins: [],
- modules: true,
- rootDir: process.cwd(),
- sassOptions: {},
- lessOptions: {},
- stylusOptions: {},
- fileIsModule: null
- };
- const postCSSPlugin = ({
- plugins = [],
- modules = true,
- rootDir = process.cwd(),
- sassOptions = {},
- lessOptions = {},
- stylusOptions = {},
- fileIsModule
- } = defaultOptions) => ({
- name: "postcss2",
- setup(build) {
- const tmpDirPath = tmp.dirSync().name, modulesMap = [];
- const modulesPlugin = postcssModules({
- generateScopedName: "[name]__[local]___[hash:base64:5]",
- ...typeof modules !== "boolean" ? modules : {},
- getJSON(filepath, json, outpath) {
- const mapIndex = modulesMap.findIndex((m) => m.path === filepath);
- if (mapIndex !== -1) {
- modulesMap[mapIndex].map = json;
- } else {
- modulesMap.push({
- path: filepath,
- map: json
- });
- }
- if (typeof modules !== "boolean" && typeof modules.getJSON === "function")
- return modules.getJSON(filepath, json, outpath);
- }
- });
- build.onResolve({filter: /.\.(css|sass|scss|less|styl)$/}, async (args) => {
- if (args.namespace !== "file" && args.namespace !== "")
- return;
- let sourceFullPath = resolveFile(args.path);
- if (!sourceFullPath)
- sourceFullPath = path.resolve(args.resolveDir, args.path);
- const sourceExt = path.extname(sourceFullPath);
- const sourceBaseName = path.basename(sourceFullPath, sourceExt);
- const isModule = fileIsModule ? fileIsModule(sourceFullPath) : sourceBaseName.match(/\.module$/);
- const sourceDir = path.dirname(sourceFullPath);
- const watchFiles = [sourceFullPath];
- let tmpFilePath;
- if (args.kind === "entry-point") {
- const sourceRelDir = path.relative(path.dirname(rootDir), path.dirname(sourceFullPath));
- tmpFilePath = path.resolve(tmpDirPath, sourceRelDir, `${sourceBaseName}.css`);
- await ensureDir(path.dirname(tmpFilePath));
- } else {
- const uniqueTmpDir = path.resolve(tmpDirPath, uniqueId());
- tmpFilePath = path.resolve(uniqueTmpDir, `${sourceBaseName}.css`);
- }
- await ensureDir(path.dirname(tmpFilePath));
- const fileContent = await readFile(sourceFullPath);
- let css = sourceExt === ".css" ? fileContent : "";
- if (sourceExt === ".sass" || sourceExt === ".scss") {
- const sassResult = await renderSass({
- ...sassOptions,
- file: sourceFullPath
- });
- css = sassResult.css.toString();
- watchFiles.push(...sassResult.stats.includedFiles);
- }
- if (sourceExt === ".styl")
- css = await renderStylus(new TextDecoder().decode(fileContent), {
- ...stylusOptions,
- filename: sourceFullPath
- });
- if (sourceExt === ".less")
- css = (await less.render(new TextDecoder().decode(fileContent), {
- ...lessOptions,
- filename: sourceFullPath,
- rootpath: path.dirname(args.path)
- })).css;
- const result = await postcss(isModule ? [modulesPlugin, ...plugins] : plugins).process(css, {
- from: sourceFullPath,
- to: tmpFilePath
- });
- watchFiles.push(...getPostCssDependencies(result.messages));
- await writeFile(tmpFilePath, result.css);
- return {
- namespace: isModule ? "postcss-module" : "file",
- path: tmpFilePath,
- watchFiles,
- pluginData: {
- originalPath: sourceFullPath
- }
- };
- });
- build.onLoad({filter: /.*/, namespace: "postcss-module"}, async (args) => {
- const mod = modulesMap.find(({path: path2}) => path2 === args?.pluginData?.originalPath), resolveDir = path.dirname(args.path);
- return {
- resolveDir,
- contents: `import ${JSON.stringify(args.path)};
- export default ${JSON.stringify(mod && mod.map ? mod.map : {})};`
- };
- });
- }
- });
- function renderSass(options) {
- return new Promise((resolve, reject) => {
- getSassImpl().render(options, (e, res) => {
- if (e)
- reject(e);
- else
- resolve(res);
- });
- });
- }
- function renderStylus(str, options) {
- return new Promise((resolve, reject) => {
- stylus.render(str, options, (e, res) => {
- if (e)
- reject(e);
- else
- resolve(res);
- });
- });
- }
- function getSassImpl() {
- let impl = "sass";
- try {
- require.resolve("sass");
- } catch {
- try {
- require.resolve("node-sass");
- impl = "node-sass";
- } catch {
- throw new Error('Please install "sass" or "node-sass" package');
- }
- }
- return require(impl);
- }
- function getFilesRecursive(directory) {
- return readdirSync(directory).reduce((files, file) => {
- const name = path.join(directory, file);
- return statSync(name).isDirectory() ? [...files, ...getFilesRecursive(name)] : [...files, name];
- }, []);
- }
- let idCounter = 0;
- function uniqueId() {
- return Date.now().toString(16) + (idCounter++).toString(16);
- }
- function getPostCssDependencies(messages) {
- let dependencies = [];
- for (const message of messages) {
- if (message.type == "dir-dependency") {
- dependencies.push(...getFilesRecursive(message.dir));
- } else if (message.type == "dependency") {
- dependencies.push(message.file);
- }
- }
- return dependencies;
- }
- var src_default = postCSSPlugin;
- export {
- src_default as default,
- defaultOptions
- };
|