wechat
parent
7eb7e05bf4
commit
18708200b3
|
|
@ -96,9 +96,10 @@
|
|||
"jest": "^25.4.0",
|
||||
"mini-types": "*",
|
||||
"miniprogram-api-typings": "*",
|
||||
"node-sass": "^4.14.1",
|
||||
"postcss-comment": "^2.0.0",
|
||||
"sass-loader": "^10.1.1",
|
||||
"postcss-windicss": "file:src/vendor/postcss-windicss",
|
||||
"sass": "^1.43.4",
|
||||
"sass-loader": "^8.0.2",
|
||||
"stylus": "^0.54.8",
|
||||
"stylus-loader": "^3.0.2",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const config = {
|
||||
|
||||
parser: require('postcss-comment'),
|
||||
plugins: [
|
||||
require('postcss-windicss')({}),
|
||||
require('postcss-import')({
|
||||
resolve (id, basedir, importOptions) {
|
||||
if (id.startsWith('~@/')) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
## Project setup
|
||||
```
|
||||
自定义插件
|
||||
```
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
dist
|
||||
node_modules
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"env": {
|
||||
"jest": true
|
||||
},
|
||||
"extends": ["@antfu"],
|
||||
"plugins": ["jest"],
|
||||
"rules": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Node template
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# We use pnpm instead of npm in this project.
|
||||
package-lock.json
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# Nuxt generate
|
||||
!dist
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
declare const postcss = true;
|
||||
|
||||
export { postcss };
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var __defProp = Object.defineProperty;
|
||||
var __defProps = Object.defineProperties;
|
||||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
||||
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
||||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
||||
var __spreadValues = (a, b) => {
|
||||
for (var prop in b || (b = {}))
|
||||
if (__hasOwnProp.call(b, prop))
|
||||
__defNormalProp(a, prop, b[prop]);
|
||||
if (__getOwnPropSymbols)
|
||||
for (var prop of __getOwnPropSymbols(b)) {
|
||||
if (__propIsEnum.call(b, prop))
|
||||
__defNormalProp(a, prop, b[prop]);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
||||
|
||||
// src/index.ts
|
||||
var _exithook = require('exit-hook'); var _exithook2 = _interopRequireDefault(_exithook);
|
||||
var _postcss = require('postcss');
|
||||
var _pluginutils = require('@windicss/plugin-utils');
|
||||
|
||||
// src/dev.ts
|
||||
var _fs = require('fs');
|
||||
var _chokidar = require('chokidar'); var _chokidar2 = _interopRequireDefault(_chokidar);
|
||||
|
||||
// src/utils.ts
|
||||
|
||||
async function touch(path, mode = "utime") {
|
||||
if (mode === "utime")
|
||||
return await touchUtime(path);
|
||||
else
|
||||
return await touchInsert(path);
|
||||
}
|
||||
var TOUCH_REG = /\/\*\s*windicss-touch:.*\*\//;
|
||||
async function touchInsert(path) {
|
||||
let css = await _fs.promises.readFile(path, "utf-8");
|
||||
const banner = `/* windicss-touch: ${Date.now()} */`;
|
||||
let replaced = false;
|
||||
css = css.replace(TOUCH_REG, () => {
|
||||
replaced = true;
|
||||
return banner;
|
||||
});
|
||||
if (!replaced)
|
||||
css = `${banner}
|
||||
${css}`;
|
||||
await _fs.promises.writeFile(path, css, "utf-8");
|
||||
}
|
||||
async function touchUtime(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const time = new Date();
|
||||
_fs.utimes.call(void 0, path, time, time, (err) => {
|
||||
if (err) {
|
||||
return _fs.open.call(void 0, path, "w", (err2, fd) => {
|
||||
if (err2)
|
||||
return reject(err2);
|
||||
_fs.close.call(void 0, fd, (err3) => err3 ? reject(err3) : resolve(fd));
|
||||
});
|
||||
}
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// src/context.ts
|
||||
var _debug2 = require('debug'); var _debug3 = _interopRequireDefault(_debug2);
|
||||
var context = {};
|
||||
var isDev = process.env.NODE_ENV === "development";
|
||||
var debug = _debug3.default.call(void 0, "postcss-windicss");
|
||||
|
||||
// src/dev.ts
|
||||
var watcher;
|
||||
function shutdownWatcher() {
|
||||
if (watcher) {
|
||||
debug("shutting down watcher");
|
||||
watcher.close();
|
||||
watcher = void 0;
|
||||
}
|
||||
}
|
||||
async function startDevWatcher(options = {}) {
|
||||
shutdownWatcher();
|
||||
debug("starting dev watcher");
|
||||
const utils = context.utils;
|
||||
await utils.ensureInit();
|
||||
const {
|
||||
touchMode = "utime"
|
||||
} = options;
|
||||
watcher = _chokidar2.default.watch(utils.options.scanOptions.include, {
|
||||
ignored: utils.options.scanOptions.exclude,
|
||||
ignoreInitial: true
|
||||
});
|
||||
if (utils.configFilePath)
|
||||
watcher.add(utils.configFilePath);
|
||||
watcher.on("change", async (path) => {
|
||||
if (path === context.entry)
|
||||
return;
|
||||
if (path === utils.configFilePath) {
|
||||
debug("reload config", utils.configFilePath);
|
||||
utils.init();
|
||||
return;
|
||||
}
|
||||
debug("update from", path);
|
||||
await utils.extractFile(await _fs.promises.readFile(path, "utf-8"));
|
||||
if (context.entry)
|
||||
touch(context.entry, touchMode);
|
||||
});
|
||||
if (context.entry)
|
||||
touch(context.entry, touchMode);
|
||||
}
|
||||
|
||||
// src/index.ts
|
||||
var plugin = (options) => {
|
||||
if (!context.utils) {
|
||||
context.utils = _pluginutils.createUtils.call(void 0, __spreadProps(__spreadValues({}, options), {
|
||||
onOptionsResolved() {
|
||||
if (isDev)
|
||||
setTimeout(() => startDevWatcher(options));
|
||||
}
|
||||
}), {
|
||||
name: "postcss-windicss"
|
||||
});
|
||||
if (isDev)
|
||||
_exithook2.default.call(void 0, shutdownWatcher);
|
||||
debug(isDev ? "development mode" : "production mode");
|
||||
}
|
||||
const utils = context.utils;
|
||||
return (root) => {
|
||||
const promiseArray = [];
|
||||
root.walkAtRules((atRule) => {
|
||||
var _a;
|
||||
const entry = (_a = atRule.root().source) == null ? void 0 : _a.input.from;
|
||||
if (atRule.name === "windicss") {
|
||||
context.entry = entry;
|
||||
promiseArray.push(utils.generateCSS().then((data) => {
|
||||
atRule.replaceWith(_postcss.parse.call(void 0, data));
|
||||
}));
|
||||
} else if (["apply"].includes(atRule.name)) {
|
||||
const rule = atRule.parent;
|
||||
if (!rule)
|
||||
return;
|
||||
promiseArray.push(utils.ensureInit().then(() => {
|
||||
const css = rule.toString();
|
||||
const transformed = css ? utils.transformCSS(css, entry || "") : void 0;
|
||||
if (transformed)
|
||||
rule.replaceWith(_postcss.parse.call(void 0, transformed));
|
||||
}));
|
||||
} else if (["screen", "variants"].includes(atRule.name)) {
|
||||
promiseArray.push(utils.ensureInit().then(() => {
|
||||
const css = atRule.toString();
|
||||
const transformed = css ? utils.transformCSS(css, entry || "") : void 0;
|
||||
if (transformed)
|
||||
atRule.replaceWith(_postcss.parse.call(void 0, transformed));
|
||||
}));
|
||||
}
|
||||
});
|
||||
root.walkDecls((decl) => {
|
||||
const match = decl.value.match(/^\s*theme\((['"])(.*)\1\)\s*$/);
|
||||
if (match && match[2])
|
||||
decl.value = utils.processor.theme(match[2]).toString();
|
||||
});
|
||||
return Promise.all(promiseArray);
|
||||
};
|
||||
};
|
||||
var postcss = true;
|
||||
plugin.postcss = true;
|
||||
module.exports = _postcss.plugin.call(void 0, "postcss-windicss", plugin);
|
||||
|
||||
|
||||
exports.postcss = postcss;
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
module.exports = {
|
||||
roots: [
|
||||
'<rootDir>/test',
|
||||
],
|
||||
testMatch: [
|
||||
'**/__tests__/**/*.+(ts|tsx|js)',
|
||||
'**/?(*.)+(spec|test).+(ts|tsx|js)',
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.(ts|tsx)$': 'ts-jest',
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"name": "postcss-windicss",
|
||||
"version": "1.0.0",
|
||||
"keywords": [
|
||||
"postcss",
|
||||
"postcss-plugin",
|
||||
"windicss"
|
||||
],
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"prepublishOnly": "npm run build",
|
||||
"dev": "npm run build -- --watch",
|
||||
"build": "tsup src/index.ts --format cjs --dts",
|
||||
"release": "bumpp --commit --push --tag",
|
||||
"lint": "eslint \"{src,test}/**/*.ts\"",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@windicss/plugin-utils": "^0.16.0",
|
||||
"chokidar": "^3.5.1",
|
||||
"debug": "^4.3.2",
|
||||
"exit-hook": "^2.2.1",
|
||||
"windicss": "^3.0.12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"postcss": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^0.6.5",
|
||||
"@antfu/ni": "^0.7.0",
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/node": "^15.6.1",
|
||||
"bumpp": "^6.0.6",
|
||||
"eslint": "^7.27.0",
|
||||
"eslint-plugin-jest": "^24.3.6",
|
||||
"esno": "^0.5.0",
|
||||
"git-ensure": "^0.1.0",
|
||||
"jest": "^27.0.1",
|
||||
"postcss": "^7.0.39",
|
||||
"ts-jest": "^27.0.1",
|
||||
"tsup": "^4.11.1",
|
||||
"typescript": "^4.3.2"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { WindiPluginUtils, WindiPluginUtilsOptions } from '@windicss/plugin-utils'
|
||||
import _debug from 'debug'
|
||||
|
||||
export interface WindiPostCSSPluginOptions extends WindiPluginUtilsOptions {
|
||||
/**
|
||||
* By default, this plugin "touches" your css entry by updating the file's
|
||||
* "updated time" (utime) to trigger the hot reload without changing its content.
|
||||
*
|
||||
* It should work most of the time. But for some tools, they might also compare
|
||||
* the file's content to avoid unnecessary hot reloads. In that cases, you will
|
||||
* need to specify this option to "insert-comment" to get proper style updates with
|
||||
* those tools.
|
||||
*
|
||||
* @default 'utime'
|
||||
*/
|
||||
touchMode?: 'utime' | 'insert-comment'
|
||||
}
|
||||
|
||||
export interface Context {
|
||||
entry?: string
|
||||
utils?: WindiPluginUtils
|
||||
}
|
||||
|
||||
export const context: Context = {}
|
||||
|
||||
export const isDev = process.env.NODE_ENV === 'development'
|
||||
export const debug = _debug('postcss-windicss')
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
import { promises as fs } from 'fs'
|
||||
import chokidar, { FSWatcher } from 'chokidar'
|
||||
import { touch } from './utils'
|
||||
import { context, debug, WindiPostCSSPluginOptions } from './context'
|
||||
|
||||
let watcher: FSWatcher | undefined
|
||||
|
||||
export function shutdownWatcher() {
|
||||
if (watcher) {
|
||||
debug('shutting down watcher')
|
||||
watcher.close()
|
||||
watcher = undefined
|
||||
}
|
||||
}
|
||||
|
||||
export async function startDevWatcher(options: WindiPostCSSPluginOptions = {}) {
|
||||
shutdownWatcher()
|
||||
|
||||
debug('starting dev watcher')
|
||||
const utils = context.utils!
|
||||
await utils.ensureInit()
|
||||
|
||||
const {
|
||||
touchMode = 'utime',
|
||||
} = options
|
||||
|
||||
watcher = chokidar
|
||||
.watch(utils.options.scanOptions.include, {
|
||||
ignored: utils.options.scanOptions.exclude,
|
||||
ignoreInitial: true,
|
||||
})
|
||||
|
||||
if (utils.configFilePath)
|
||||
watcher.add(utils.configFilePath)
|
||||
|
||||
watcher
|
||||
.on('change', async(path) => {
|
||||
if (path === context.entry)
|
||||
return
|
||||
if (path === utils.configFilePath) {
|
||||
debug('reload config', utils.configFilePath)
|
||||
utils.init()
|
||||
return
|
||||
}
|
||||
|
||||
debug('update from', path)
|
||||
await utils!.extractFile(await fs.readFile(path, 'utf-8'))
|
||||
if (context.entry)
|
||||
touch(context.entry, touchMode)
|
||||
})
|
||||
|
||||
if (context.entry)
|
||||
touch(context.entry, touchMode)
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
import exitHook from 'exit-hook'
|
||||
import { parse, plugin as PostcssPlugin } from 'postcss'
|
||||
import { createUtils } from '@windicss/plugin-utils'
|
||||
// import type { Plugin } from 'postcss'
|
||||
import { shutdownWatcher, startDevWatcher } from './dev'
|
||||
import { context, debug, isDev, WindiPostCSSPluginOptions } from './context'
|
||||
|
||||
const plugin = (options: WindiPostCSSPluginOptions): any => {
|
||||
if (!context.utils) {
|
||||
context.utils = createUtils({
|
||||
...options,
|
||||
onOptionsResolved() {
|
||||
if (isDev)
|
||||
setTimeout(() => startDevWatcher(options))
|
||||
},
|
||||
}, {
|
||||
name: 'postcss-windicss',
|
||||
})
|
||||
|
||||
if (isDev)
|
||||
exitHook(shutdownWatcher)
|
||||
|
||||
debug(isDev ? 'development mode' : 'production mode')
|
||||
}
|
||||
|
||||
const utils = context.utils
|
||||
|
||||
return (root) => {
|
||||
const promiseArray: any[] = []
|
||||
root.walkAtRules((atRule) => {
|
||||
const entry = atRule.root().source?.input.from
|
||||
if (atRule.name === 'windicss') {
|
||||
context.entry = entry
|
||||
promiseArray.push(utils.generateCSS().then((data) => {
|
||||
atRule.replaceWith(parse(data))
|
||||
}))
|
||||
// atRule.replaceWith(parse(await utils.generateCSS()))
|
||||
}
|
||||
// @apply
|
||||
else if (['apply'].includes(atRule.name)) {
|
||||
const rule = atRule.parent!
|
||||
if (!rule)
|
||||
return
|
||||
|
||||
// await utils.ensureInit()
|
||||
promiseArray.push(utils.ensureInit().then(() => {
|
||||
const css = rule.toString()
|
||||
const transformed = css ? utils.transformCSS(css, entry || '') : undefined
|
||||
if (transformed)
|
||||
rule.replaceWith(parse(transformed))
|
||||
}))
|
||||
}
|
||||
// @screen, @variants
|
||||
else if (['screen', 'variants'].includes(atRule.name)) {
|
||||
// await utils.ensureInit()
|
||||
promiseArray.push(utils.ensureInit().then(() => {
|
||||
const css = atRule.toString()
|
||||
const transformed = css ? utils.transformCSS(css, entry || '') : undefined
|
||||
if (transformed)
|
||||
atRule.replaceWith(parse(transformed))
|
||||
}))
|
||||
}
|
||||
})
|
||||
root.walkDecls((decl) => {
|
||||
// We work with each `decl` object here.
|
||||
const match = decl.value.match(/^\s*theme\((['"])(.*)\1\)\s*$/)
|
||||
if (match && match[2])
|
||||
decl.value = (utils.processor.theme(match[2]) as any).toString()
|
||||
})
|
||||
return Promise.all(promiseArray)
|
||||
}
|
||||
|
||||
// return {
|
||||
// postcssPlugin: 'postcss-windicss',
|
||||
// async AtRule(atRule) {
|
||||
// const entry = atRule.root().source?.input.from
|
||||
// if (atRule.name === 'windicss') {
|
||||
// context.entry = entry
|
||||
// atRule.replaceWith(parse(await utils.generateCSS()))
|
||||
// }
|
||||
// // @apply
|
||||
// else if (['apply'].includes(atRule.name)) {
|
||||
// const rule = atRule.parent!
|
||||
// if (!rule)
|
||||
// return
|
||||
|
||||
// await utils.ensureInit()
|
||||
// const css = rule.toString()
|
||||
// const transformed = css ? utils.transformCSS(css, entry || '') : undefined
|
||||
// if (transformed)
|
||||
// rule.replaceWith(parse(transformed))
|
||||
// }
|
||||
// // @screen, @variants
|
||||
// else if (['screen', 'variants'].includes(atRule.name)) {
|
||||
// await utils.ensureInit()
|
||||
// const css = atRule.toString()
|
||||
// const transformed = css ? utils.transformCSS(css, entry || '') : undefined
|
||||
// if (transformed)
|
||||
// atRule.replaceWith(parse(transformed))
|
||||
// }
|
||||
// },
|
||||
// Declaration(decl) {
|
||||
// // theme()
|
||||
// const match = decl.value.match(/^\s*theme\((['"])(.*)\1\)\s*$/)
|
||||
// if (match && match[2])
|
||||
// decl.value = (utils.processor.theme(match[2]) as any).toString()
|
||||
// },
|
||||
// }
|
||||
}
|
||||
|
||||
export const postcss = true
|
||||
|
||||
plugin.postcss = true
|
||||
|
||||
module.exports = PostcssPlugin('postcss-windicss', plugin)
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import { promises as fs, utimes, open, close } from 'fs'
|
||||
|
||||
export async function touch(path: string, mode: 'utime' | 'insert-comment' = 'utime') {
|
||||
if (mode === 'utime')
|
||||
return await touchUtime(path)
|
||||
else
|
||||
return await touchInsert(path)
|
||||
}
|
||||
|
||||
const TOUCH_REG = /\/\*\s*windicss-touch:.*\*\//
|
||||
|
||||
export async function touchInsert(path: string) {
|
||||
let css = await fs.readFile(path, 'utf-8')
|
||||
const banner = `/* windicss-touch: ${Date.now()} */`
|
||||
let replaced = false
|
||||
css = css.replace(TOUCH_REG, () => {
|
||||
replaced = true
|
||||
return banner
|
||||
})
|
||||
if (!replaced)
|
||||
css = `${banner}\n${css}`
|
||||
await fs.writeFile(path, css, 'utf-8')
|
||||
}
|
||||
|
||||
export async function touchUtime(path: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const time = new Date()
|
||||
utimes(path, time, time, (err) => {
|
||||
if (err) {
|
||||
return open(path, 'w', (err, fd) => {
|
||||
if (err)
|
||||
return reject(err)
|
||||
close(fd, err => (err ? reject(err) : resolve(fd)))
|
||||
})
|
||||
}
|
||||
resolve(false)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2017",
|
||||
"module": "esnext",
|
||||
"lib": ["esnext"],
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"strict": false,
|
||||
"strictNullChecks": true,
|
||||
"resolveJsonModule": true
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue