feat: 完善 vite build

This commit is contained in:
winixt 2022-04-04 15:32:41 +08:00
parent f9397495c4
commit 51ebe58a29
24 changed files with 131 additions and 58 deletions

View File

@ -1,29 +1,47 @@
import legacy from '@vitejs/plugin-legacy';
import { getInnerCommonConfig } from '../../common/getConfig';
/**
* polyfill @vitejs/plugin-legacy
* 确认 css 最终构建实现 autoprefixer postcss-safe-parser postcss-flexbugs-fixes
*/
export default async (api) => {
const { deepmerge } = api.utils;
const { deepmerge, getTargetsAndBrowsersList } = api.utils;
const { build = {} } = api.config.viteOption;
const { browserslist } = getTargetsAndBrowsersList({ config: api.config });
return deepmerge(
const bundleConfig = deepmerge(
{
mode: 'production',
css: {
postcss: {
plugins: [require('postcss-flexbugs-fixes'), require('postcss-safe-parser'), [require('autoprefixer'), {}]],
plugins: [
require('postcss-flexbugs-fixes'),
require('postcss-safe-parser'),
require('autoprefixer')({
...api.config.autoprefixer,
overrideBrowserslist: browserslist,
}),
],
},
},
plugins: [
legacy({
targets: browserslist,
...api.config.viteLegacy,
}),
],
build: {
...build,
target: build.target || 'es2015',
outDir: build.outDir || api.config.outputPath || 'dist',
assetsInlineLimit: build.assetsInlineLimit || api.config.inlineLimit || 8192,
},
},
getInnerCommonConfig(api),
);
return api.applyPlugins({
type: api.ApplyPluginsType.modify,
key: 'modifyBundleConfig',
initialValue: bundleConfig,
args: {},
});
};

View File

@ -24,12 +24,13 @@ export default async (api, args) => {
args: {},
});
return deepmerge(
const bundleConfig = deepmerge(
{
mode: 'development',
plugins: [viteMiddlewarePlugin(beforeMiddlewares, middlewares)],
server: {
...server,
proxy: server?.proxy || api.config.proxy,
port,
host: hostname,
https: process.env.HTTPS || args.https,
@ -37,4 +38,11 @@ export default async (api, args) => {
},
getInnerCommonConfig(api),
);
return api.applyPlugins({
type: api.ApplyPluginsType.modify,
key: 'modifyBundleConfig',
initialValue: bundleConfig,
args: {},
});
};

View File

@ -3,11 +3,6 @@ import getDevConfig from './getDevConfig';
/**
* TODO
*
* analyze: rollup-plugin-visualizer
*
* 其他插件如何对内部配置进行修改
*
* 共享 webpack vite 的部分配置降低熟悉 vite 的成本
*/

View File

@ -5,11 +5,8 @@ import { createHtmlPlugin } from 'vite-plugin-html';
import SFCConfigBlockPlugin from './SFCConfigBlockPlugin';
import getDefine from './getDefine';
// TODO
// * 如何处理 html (改 mountId or title 等)(比较麻烦,晚点再看看有无更好的方案)
export function getInnerCommonConfig(api) {
const { deepmerge } = api.utils;
const { deepmerge, resolveRuntimeEnv } = api.utils;
const { server, build, define, base, ...otherViteOption } = api.config.viteOption;
const publicPath = base || api.config.publicPath || '/';
@ -27,10 +24,10 @@ export function getInnerCommonConfig(api) {
createHtmlPlugin({
minify: true,
entry: join(api.paths.absTmpPath, 'fes.js'),
template: 'public/index.html',
template: 'index.html',
inject: {
data: {
title: 'Fes.js',
...resolveRuntimeEnv(publicPath),
mountElementId: api.config.mountElementId,
},
},

View File

@ -3,10 +3,24 @@ export default (api) => {
key: 'viteAnalyze',
config: {
schema(joi) {
return joi.object({}).unknown(true);
return joi.object();
},
default: {},
},
enableBy: () => !!process.env.ANALYZE,
});
api.modifyBundleConfig((memo) => {
memo.plugins.push(
require('rollup-plugin-visualizer').visualizer({
filename: './.cache/visualizer/stats.html',
open: true,
gzipSize: true,
brotliSize: true,
...api.viteAnalyze,
}),
);
return memo;
});
};

View File

@ -0,0 +1,12 @@
export default (api) => {
api.describe({
key: 'viteHtml',
config: {
schema(joi) {
return joi.object();
},
default: {},
},
enableBy: () => !!process.env.ANALYZE,
});
};

View File

@ -0,0 +1,12 @@
export default (api) => {
api.describe({
key: 'viteLegacy',
config: {
schema(joi) {
return joi.object();
},
default: {},
},
enableBy: () => !!process.env.ANALYZE,
});
};

View File

@ -1,10 +1,15 @@
export default function () {
return {
plugins: [
require.resolve('./registerMethods'),
require.resolve('./registerType'),
// bundle configs
require.resolve('./features/viteOption'),
require.resolve('./features/viteVueJsx'),
require.resolve('./features/viteVuePlugin'),
require.resolve('./features/viteAnalyze'),
require.resolve('./features/viteLegacy'),
// commands
require.resolve('./commands/build'),

View File

@ -0,0 +1,5 @@
export default function (api) {
['modifyBundleConfig'].forEach((name) => {
api.registerMethod({ name });
});
}

View File

@ -0,0 +1,8 @@
import { name } from '../package.json';
export default function (api) {
api.addConfigType(() => ({
source: name,
build: ['ViteBuildConfig'],
}));
}

View File

@ -1,10 +1,14 @@
import type {UserConfig} from 'vite';
import type {Options} from '@vitejs/plugin-vue'
import {Options as PolyfillOptions } from '@vitejs/plugin-legacy'
import createPlugin from '@vitejs/plugin-vue-jsx'
import {createHtmlPlugin} from 'vite-plugin-html'
export interface ViteBuildConfig {
viteOption: UserConfig;
viteVuePlugin: Options;
viteVueJsx: Parameters<typeof createPlugin>[0];
viteLegacy: PolyfillOptions;
viteHtml: Parameters<typeof createHtmlPlugin>[0]
}

View File

@ -25,7 +25,6 @@ export default function () {
require.resolve('./plugins/features/outputPath'),
require.resolve('./plugins/features/postcssLoader'),
require.resolve('./plugins/features/publicPath'),
require.resolve('./plugins/features/targets'),
require.resolve('./plugins/features/terserOptions'),
require.resolve('./plugins/features/nodeModulesTransform'),
require.resolve('./plugins/features/vueLoader'),

View File

@ -167,8 +167,6 @@ export function printFileSizes(stats, dir) {
console.log(`${ui.toString()}\n\n ${chalk.gray('Images and other types of assets omitted.')}\n`);
if (orderedAssets?.some((asset) => asset.suggested)) {
// We'll warn for bundles exceeding them.
// TODO: use umi docs
console.log();
console.log(chalk.yellow('The bundle size is significantly larger than recommended.'));
console.log(chalk.yellow('Consider reducing it with code splitting'));

View File

@ -9,24 +9,6 @@ import createDefineWebpackConfig from './define';
import createMinimizerWebpackConfig from './minimizer';
import createHtmlWebpackConfig from './html';
function getTargetsAndBrowsersList({ config }) {
let targets = config.targets || {};
targets = Object.keys(targets)
.filter((key) => targets[key] !== false)
.reduce((memo, key) => {
memo[key] = targets[key];
return memo;
}, {});
const browserslist = targets.browsers || Object.keys(targets).map((key) => `${key} >= ${targets[key] === true ? '0' : targets[key]}`);
return {
targets,
browserslist,
};
}
const DEFAULT_EXCLUDE_NODE_MODULES = [
'vue',
'vuex',
@ -139,7 +121,7 @@ export default async function getConfig({ api, cwd, config, env, entry = {}, mod
esModule: false,
});
const { targets, browserslist } = getTargetsAndBrowsersList({ config });
const { targets, browserslist } = api.utils.getTargetsAndBrowsersList({ config });
const babelOpts = await getBabelOpts({
cwd,
config,

View File

@ -15,8 +15,6 @@ import mergeDefault from './utils/mergeDefault';
const CONFIG_FILES = ['.fes.js'];
// TODO:
// 1. custom config file
export default class Config {
cwd;

View File

@ -21,6 +21,7 @@ export default function () {
require.resolve('./plugins/features/plugins'),
require.resolve('./plugins/features/proxy'),
require.resolve('./plugins/features/singular'),
require.resolve('./plugins/features/targets'),
// route
require.resolve('./plugins/route'),

View File

@ -2,13 +2,16 @@ import { extname } from 'path';
import historyFallback from 'connect-history-api-fallback';
const ASSET_EXT_NAMES = ['.ico', '.png', '.jpg', '.jpeg', '.gif', '.svg'];
const SKIP_PATHS_PREFIX = ['/@vite', '/@id'];
const proxyMiddleware = (api) => (req, res, next) => {
const proxyConfig = api.config.proxy;
if (proxyConfig && Object.keys(proxyConfig).some((path) => req.url.startsWith(path))) {
return next();
}
if (SKIP_PATHS_PREFIX.find((prefix) => req.url.startsWith(prefix))) {
return next();
}
if (ASSET_EXT_NAMES.includes(extname(req.url))) {
return next();
}

View File

@ -3,11 +3,10 @@ export default (api) => {
key: 'targets',
config: {
default: {
chrome: 49,
firefox: 64,
safari: 10,
chrome: 56,
firefox: 67,
safari: 10.4,
edge: 13,
ios: 10,
},
schema(joi) {
return joi.object();

View File

@ -1,4 +1,3 @@
// TODO 其他 API
export {
useRoute,
useRouter,
@ -10,7 +9,7 @@ export {
createWebHashHistory,
createWebHistory,
createMemoryHistory,
createRouter
createRouter,
} from 'vue-router';
export { default as Plugin, ApplyPluginsType } from './plugin';

View File

@ -11,15 +11,12 @@
<meta name="viewport"
content="viewport-fit=cover,width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no">
<title>
<%= title %>
Fes & vite
</title>
<link rel="shortcut icon" type="image/x-icon" href="./logo.png">
</head>
<body ontouchstart="">
<div id="<%= mountElementId %>"></div>
<script type="module" src="/src/.fes/fes.js"></script>
<!-- built files will be auto injected -->
</body>
</html>

View File

@ -4,7 +4,8 @@
"description": "fes vite 构建模版",
"scripts": {
"prod": "FES_ENV=prod fes build",
"dev": "fes dev"
"dev": "fes dev",
"analyze": "ANALYZE=1 fes build"
},
"keywords": [
"管理端",

View File

@ -1,4 +1,3 @@
// TODO
// 时间格式化
// js 数字精度计算
// 手机号、身份证号 等的校验

View File

@ -0,0 +1,17 @@
export default function getTargetsAndBrowsersList({ config }) {
let targets = config.targets || {};
targets = Object.keys(targets)
.filter((key) => targets[key] !== false)
.reduce((memo, key) => {
memo[key] = targets[key];
return memo;
}, {});
const browserslist = targets.browsers || Object.keys(targets).map((key) => `${key} >= ${targets[key] === true ? '0' : targets[key]}`);
return {
targets,
browserslist,
};
}

View File

@ -31,6 +31,7 @@ import changePort from './changePort';
import getHostName from './getHostName';
import resolveRuntimeEnv from './resolveRuntimeEnv';
import stringifyObjValue from './stringifyObjValue';
import getTargetsAndBrowsersList from './getTargetsAndBrowsersList';
export {
chalk,
@ -68,4 +69,5 @@ export {
getHostName,
resolveRuntimeEnv,
stringifyObjValue,
getTargetsAndBrowsersList,
};