feat: 构建类型定义

This commit is contained in:
winixt 2022-03-28 19:44:54 +08:00
parent a2425b7236
commit 64adb679c8
10 changed files with 85 additions and 95 deletions

View File

@ -5,23 +5,11 @@
import { existsSync } from 'fs';
import { extname, join } from 'path';
import {
chalk,
chokidar,
compatESModuleRequire,
deepmerge,
cleanRequireCache,
lodash,
parseRequireDeps,
winPath
} from '@fesjs/utils';
import { chalk, chokidar, compatESModuleRequire, deepmerge, cleanRequireCache, lodash, parseRequireDeps, winPath } from '@fesjs/utils';
import assert from 'assert';
import joi from 'joi';
import { ServiceStage } from '../service/enums';
import {
getUserConfigWithKey,
updateUserConfigWithKey
} from './utils/configUtils';
import { getUserConfigWithKey, updateUserConfigWithKey } from './utils/configUtils';
import isEqual from './utils/isEqual';
import mergeDefault from './utils/mergeDefault';
@ -60,17 +48,12 @@ export default class Config {
}
getConfig({ defaultConfig }) {
assert(
this.service.stage >= ServiceStage.pluginReady,
'Config.getConfig() failed, it should not be executed before plugin is ready.'
);
assert(this.service.stage >= ServiceStage.pluginReady, 'Config.getConfig() failed, it should not be executed before plugin is ready.');
const userConfig = this.getUserConfig();
// 用于提示用户哪些 key 是未定义的
// TODO: 考虑不排除 false 的 key
const userConfigKeys = Object.keys(userConfig).filter(
key => userConfig[key] !== false
);
const userConfigKeys = Object.keys(userConfig).filter((key) => userConfig[key] !== false);
// get config
const pluginIds = Object.keys(this.service.plugins);
@ -81,22 +64,17 @@ export default class Config {
const value = getUserConfigWithKey({
key,
userConfig
userConfig,
});
// 不校验 false 的值,此时已禁用插件
if (value === false) return;
// do validate
const schema = config.schema(joi);
assert(
joi.isSchema(schema),
`schema return from plugin ${pluginId} is not valid schema.`
);
assert(joi.isSchema(schema), `schema return from plugin ${pluginId} is not valid schema.`);
const { error } = schema.validate(value);
if (error) {
const e = new Error(
`Validate config "${key}" failed, ${error.message}`
);
const e = new Error(`Validate config "${key}" failed, ${error.message}`);
e.stack = error.stack;
throw e;
}
@ -111,21 +89,19 @@ export default class Config {
if (key in defaultConfig) {
const newValue = mergeDefault({
defaultConfig: defaultConfig[key],
config: value
config: value,
});
updateUserConfigWithKey({
key,
value: newValue,
userConfig
userConfig,
});
}
});
if (userConfigKeys.length) {
const keys = userConfigKeys.length > 1 ? 'keys' : 'key';
throw new Error(
`Invalid config ${keys}: ${userConfigKeys.join(', ')}`
);
throw new Error(`Invalid config ${keys}: ${userConfigKeys.join(', ')}`);
}
return userConfig;
@ -143,7 +119,7 @@ export default class Config {
requireDeps.forEach(cleanRequireCache);
this.service.babelRegister.setOnlyMap({
key: 'config',
value: requireDeps
value: requireDeps,
});
// require config and merge
@ -173,31 +149,22 @@ export default class Config {
getConfigFile() {
// TODO: support custom config file
let configFile = CONFIG_FILES.find(f => existsSync(join(this.cwd, f)));
let configFile = CONFIG_FILES.find((f) => existsSync(join(this.cwd, f)));
if (!configFile) return [];
configFile = winPath(configFile);
let envConfigFile;
// 潜在问题:
// .local 和 .env 的配置必须有 configFile 才有效
if (process.env.FES_ENV) {
envConfigFile = this.addAffix(
configFile,
process.env.FES_ENV
);
envConfigFile = this.addAffix(configFile, process.env.FES_ENV);
if (!existsSync(join(this.cwd, envConfigFile))) {
throw new Error(
`get user config failed, ${envConfigFile} does not exist, but process.env.FES_ENV is set to ${process.env.FES_ENV}.`
);
throw new Error(`get user config failed, ${envConfigFile} does not exist, but process.env.FES_ENV is set to ${process.env.FES_ENV}.`);
}
}
const files = [
configFile,
envConfigFile,
this.localConfig && this.addAffix(configFile, 'local')
]
.filter(f => !!f)
.map(f => join(this.cwd, f))
.filter(f => existsSync(f));
const files = [configFile, envConfigFile, this.localConfig && this.addAffix(configFile, 'local')]
.filter((f) => !!f)
.map((f) => join(this.cwd, f))
.filter((f) => existsSync(f));
return files;
}
@ -221,7 +188,7 @@ export default class Config {
}
return memo;
}, [])
.filter(f => !f.startsWith(configDir));
.filter((f) => !f.startsWith(configDir));
return [configDir].concat(files);
}
@ -231,7 +198,7 @@ export default class Config {
let userConfig = opts.userConfig;
const watcher = chokidar.watch(paths, {
ignoreInitial: true,
cwd: this.cwd
cwd: this.cwd,
});
watcher.on('all', (event, path) => {
console.log(chalk.green(`[${event}] ${path}`));
@ -252,12 +219,9 @@ export default class Config {
if (!isEqual(newUserConfig[key], userConfig[key])) {
const changed = {
key,
pluginId
pluginId,
};
if (
newUserConfig[key] === false
|| userConfig[key] === false
) {
if (newUserConfig[key] === false || userConfig[key] === false) {
pluginChanged.push(changed);
} else {
valueChanged.push(changed);
@ -269,7 +233,7 @@ export default class Config {
opts.onChange({
userConfig: newUserConfig,
pluginChanged,
valueChanged
valueChanged,
});
}
userConfig = newUserConfig;

View File

@ -1,16 +1,9 @@
import {
lodash,
winPath
} from '@fesjs/utils';
import { lodash, winPath } from '@fesjs/utils';
export default class BabelRegister {
only = {};
setOnlyMap({
key,
value
}) {
setOnlyMap({ key, value }) {
this.only[key] = value;
this.register();
}
@ -19,7 +12,7 @@ export default class BabelRegister {
const only = lodash.uniq(
Object.keys(this.only)
.reduce((memo, key) => memo.concat(this.only[key]), [])
.map(winPath)
.map(winPath),
);
require('@babel/register')({
presets: [
@ -27,17 +20,17 @@ export default class BabelRegister {
require.resolve('@babel/preset-env'),
{
targets: {
node: 'current'
node: 'current',
},
modules: 'commonjs'
}
]
modules: 'commonjs',
},
],
],
ignore: [/node_modules/],
only,
extensions: ['.jsx', '.js', '.ts', '.tsx'],
babelrc: false,
cache: false
cache: false,
});
}
}

View File

@ -32,5 +32,6 @@
},
"dependencies": {
"windicss-webpack-plugin": "^1.6.0"
}
},
"typings": "./types.d.ts"
}

View File

@ -1,4 +1,5 @@
import WindiCSSWebpackPlugin from 'windicss-webpack-plugin';
import { name } from '../package.json';
export default (api) => {
api.describe({
@ -47,4 +48,9 @@ export default (api) => {
return memo;
});
api.addBuildType(() => ({
source: name,
specifier: ['WindicssBuildConfig'],
}));
};

View File

@ -0,0 +1,7 @@
import type { Config } from 'windicss/types/interfaces';
export interface WindicssBuildConfig {
windicss: {
config: Config
}
}

View File

@ -1,8 +1,8 @@
// fes.config.js 只负责管理 cli 相关的配置
import pxtoviewport from '@ttou/postcss-px-to-viewport';
import { defineBuildConfig } from '@fesjs/fes';
export default {
export default defineBuildConfig({
define: {
// __VUE_OPTIONS_API__: true,
// __VUE_PROD_DEVTOOLS__: false
@ -45,4 +45,5 @@ export default {
}
}
}
};
});

View File

@ -42,6 +42,7 @@
"@fesjs/preset-built-in": "^2.0.22",
"@fesjs/runtime": "^2.0.2",
"@fesjs/utils": "^2.0.4",
"pirates": "^4.0.5",
"resolve-cwd": "^3.0.0",
"vue-router": "^4.0.1"
},
@ -49,4 +50,4 @@
"node": "^10.12.0 || ^12.0.0 || >= 14.0.0"
},
"types": "types.d.ts"
}
}

View File

@ -4,18 +4,13 @@ import fork from './utils/fork';
import getCwd from './utils/getCwd';
import getPkg from './utils/getPkg';
import fesPkg from '../package.json';
import { hackFesInBuild } from './hackFesInBuild';
const requiredVersion = fesPkg.engines.node;
function checkNodeVersion(wanted, id) {
if (
!semver.satisfies(process.version, wanted, { includePrerelease: true })
) {
console.log(
chalk.red(
`You are using Node ${process.version}, but this version of ${id} requires Node ${wanted}.\nPlease upgrade your Node version.`
)
);
if (!semver.satisfies(process.version, wanted, { includePrerelease: true })) {
console.log(chalk.red(`You are using Node ${process.version}, but this version of ${id} requires Node ${wanted}.\nPlease upgrade your Node version.`));
process.exit(1);
}
}
@ -31,7 +26,7 @@ const args = yParser(rawArgv);
const command = args._[0];
if (command === 'dev') {
const child = fork({
scriptPath: require.resolve('./forkedDev')
scriptPath: require.resolve('./forkedDev'),
});
// ref:
// http://nodejs.cn/api/process/signal_events.html
@ -44,16 +39,17 @@ const args = yParser(rawArgv);
process.exit(1);
});
} else {
hackFesInBuild();
if (command === 'build') {
process.env.NODE_ENV = 'production';
}
await new Service({
cwd: getCwd(),
pkg: getPkg(process.cwd()),
fesPkg
fesPkg,
}).run({
args,
rawArgv
rawArgv,
});
}
} catch (e) {

View File

@ -8,6 +8,7 @@ import { Service } from './serviceWithBuiltIn';
import getCwd from './utils/getCwd';
import getPkg from './utils/getPkg';
import fesPkg from '../package.json';
import { hackFesInBuild } from './hackFesInBuild';
const args = yParser(process.argv.slice(2));
@ -21,8 +22,8 @@ function onSignal(signal, service) {
key: 'onExit',
type: service.ApplyPluginsType.event,
args: {
signal
}
signal,
},
});
process.exit(0);
}
@ -30,17 +31,17 @@ function onSignal(signal, service) {
(async () => {
try {
process.env.NODE_ENV = 'development';
hackFesInBuild();
const service = new Service({
cwd: getCwd(),
pkg: getPkg(process.cwd()),
fesPkg
fesPkg,
});
await service.run({
name: 'dev',
args
args,
});
// kill(2) Ctrl-C
process.once('SIGINT', () => onSignal('SIGINT', service));
// kill(3) Ctrl-\

View File

@ -0,0 +1,20 @@
// my-module/register.js
import { addHook } from 'pirates';
function matcher(filename) {
if (filename.endsWith('/fes/lib/index.js')) return true;
return false;
}
export function hackFesInBuild() {
addHook(
() => `
module.exports = {
defineBuildConfig(params) {
return params;
}
}
`,
{ exts: ['.js'], ignoreNodeModules: false, matcher },
);
}