stylelint执行插件的全过程

stylelint可以用来扩展插件去实现各种规则,接下来带大家看看stylelint是如何执行插件的

首先遍历absoluteFilePaths路径(该路径是我们执行lint命令配置的文件类型eslint --cache --max-warnings 0 \"{src,mock}/**/*.{vue,ts,tsx}\" --fix,.{vue,ts,tsx}这个就是匹配的文件类型)。接下来执行lintSource方法。

// node_modules\stylelint\lib\standalone.js
const getStylelintResults = absoluteFilePaths.map(async (absoluteFilepath) => {
			debug(`Processing ${absoluteFilepath}`);

			try {
				const postcssResult = await lintSource(stylelint, {
					filePath: absoluteFilepath,
					cache: useCache,
				});

				...

这里首先会获取针对当前文件类型的配置文件,该文件包括本地配置的.stylelintrc.js。

// node_modules\stylelint\lib\lintSource.js
try {
		configForFile = await getConfigForFile(stylelint, configSearchPath, inputFilePath);
	} catch (err) {
		if (isCodeNotFile && isPathNotFoundError(err)) {
			configForFile = await getConfigForFile(stylelint, cwd);
		} else {
			throw err;
		}
	}

配置文件包括当前文件要执行的plugins,我们此次要分析的是stylelint-order插件
stylelint执行插件的全过程_第1张图片

// node_modules\stylelint\lib\lintSource.js
// 读取要处理的文件内容
const postcssResult =
		existingPostcssResult ||
		(await getPostcssResult(stylelint, {
			code: options.code,
			codeFilename: options.codeFilename,
			filePath: inputFilePath,
			codeProcessors: config.codeProcessors,
			customSyntax: config.customSyntax,
		}));
// 调用插件处理
	await lintPostcssResult(stylelint._options, stylelintPostcssResult, config);
	// 处理完得到root,root的nodes,root包括处理好的样式和codeBefore、codeAfter
	return stylelintPostcssResult;

首先执行getPostcssResult方法获取要处理的文件内容,然后

// node_modules\stylelint\lib\getPostcssResult.js
if (options.code !== undefined) {
		getCode = options.code;
	} else if (options.filePath) {
		getCode = await fs.readFile(options.filePath, 'utf8');
	}

	if (getCode === undefined) {
		return Promise.reject(new Error('code or filePath required'));
	}

	if (options.codeProcessors && options.codeProcessors.length) {
		if (stylelint._options.fix) {
			console.warn(
				'Autofix is incompatible with processors and will be disabled. Are you sure you need a processor?',
			);
			stylelint._options.fix = false;
		}

		const sourceName = options.code ? options.codeFilename : options.filePath;

		for (const codeProcessor of options.codeProcessors) {
			getCode = codeProcessor(getCode, sourceName);
		}
	}
	// postcss-html插件处理读取的文件
	const postcssResult = await new LazyResult(postcssProcessor, getCode, postcssOptions);

此时获取syntax去解析已读取的文件内容,我们此处用的是postcss-html。该插件可以读取vue模板中的style样式。

// node_modules\postcss\lib\lazy-result.js
let parser = parse
if (opts.syntax) parser = opts.syntax.parse
 if (opts.parser) parser = opts.parser
 if (parser.parse) parser = parser.parse

 try {
   root = parser(css, opts)
 } catch (error) {
   this.processed = true
   this.error = error
 }

stylelint执行插件的全过程_第2张图片

stylelint执行插件的全过程_第3张图片
在lintSource.js文件中处理完毕后得到postcssResult回到standalone.js文件

// node_modules\stylelint\lib\standalone.js
if (
	postcssResult.root &&
	postcssResult.opts &&
	!postcssResult.stylelint.ignored &&
	fix &&
	!postcssResult.stylelint.disableWritingFix
) {// 将插件处理好的拼接起来
	const fixedCss = postcssResult.root.toString(postcssResult.opts.syntax);

	if (
		postcssResult.root &&
		postcssResult.root.source &&
		postcssResult.root.source.input.css !== fixedCss
	) {
		await writeFileAtomic(absoluteFilepath, fixedCss);
	}
}

此时调用postcssResult.root.toString方法拼接Root中的nodes和raws的codeBefore、codeAfter。

// node_modules\postcss-html\lib\stringify.js
if (node.nodes.length) {
		node.nodes.forEach((root) => {
			// 加上被处理样式之前
			builder(root.raws.codeBefore, root, "codeBefore");
			if (root.source.syntax) {
				// 执行builder加上已处理样式
				root.source.syntax.stringify(root, builder);
			} else {
				postcssStringify(root, builder);
			}
			// 加上被处理的样式后面
			builder(root.raws.codeAfter || "", root, "codeAfter");
		});
	} else {
		// If it do not have root, it will output the input.
		builder(node.source.input.css);
	}

此时拼接好的就是排序好的代码
stylelint执行插件的全过程_第4张图片
此时回到standalone.js执行writeFileAtomic方法覆盖原文件

// node_modules\stylelint\lib\standalone.js
if (
	postcssResult.root &&
	postcssResult.root.source &&
	postcssResult.root.source.input.css !== fixedCss
) {
	await writeFileAtomic(absoluteFilepath, fixedCss);
}

stylelint执行插件的全过程_第5张图片

总结

  1. stylelint会获取所有的需要lint的文件路径
  2. 根据路径的文件类型生成配置
  3. 使用node读取文件内容并调用配置的syntax解析文件
  4. 调用插件执行已解析的文件内容
  5. 拼接已处理的文件为完整字符串
  6. 重新写入文件覆盖原内容

你可能感兴趣的:(stylelint,前端基础,vue.js,javascript,前端)