From f44acf5c0885a3088cba710e9ed069166c23c129 Mon Sep 17 00:00:00 2001 From: bac-joker Date: Mon, 8 Feb 2021 16:52:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E5=86=99=E6=9E=84=E5=BB=BA=20?= =?UTF-8?q?&=20=E5=8D=87=E7=BA=A7=E5=88=B0=20webpack5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 +- packages/fes-compiler/package.json | 6 +- .../fes-compiler/src/service/babelRegister.js | 43 + packages/fes-compiler/src/service/index.js | 6 +- packages/fes-preset-built-in/package.json | 45 +- packages/fes-preset-built-in/src/index.js | 7 +- .../src/plugins/commands/build/build.js | 19 + .../src/plugins/commands/build/index.js | 14 +- .../commands}/buildDevUtils.js | 149 +- .../src/plugins/commands/dev/devServer.js | 46 + .../src/plugins/commands/dev/index.js | 44 +- .../src/plugins/commands/webpackConfig/css.js | 104 + .../plugins/commands/webpackConfig/define.js | 47 + .../commands/webpackConfig/getBableOpts.js | 84 + .../commands/webpackConfig/getConfig.js | 305 ++ .../plugins/commands/webpackConfig/html.js | 63 + .../webpackConfig}/index-default.html | 0 .../commands/webpackConfig/minimizer.js | 62 + .../src/plugins/commands/webpackConfig/vue.js | 28 + .../src/plugins/features/alias.js | 44 +- .../src/plugins/features/analyze.js | 6 +- .../src/plugins/features/chainWebpack.js | 39 - .../src/plugins/features/chunks.js | 11 - .../src/plugins/features/copy.js | 4 +- .../src/plugins/features/cssLoader.js | 7 +- .../src/plugins/features/cssnano.js | 16 - .../src/plugins/features/define.js | 2 - .../src/plugins/features/devScripts.js | 99 - .../src/plugins/features/extraBabelPlugins.js | 10 - .../src/plugins/features/extraBabelPresets.js | 12 - .../src/plugins/features/hardSource.js | 60 +- .../src/plugins/features/hash.js | 12 - .../src/plugins/features/html.js | 102 - .../src/plugins/features/imageMinimizer.js | 23 - .../plugins/features/nodeModulesTransform.js | 2 - .../src/plugins/features/styleLoader.js | 10 - .../src/plugins/features/targets.js | 1 - .../src/plugins/features/vueLoader.js | 21 +- .../src/plugins/registerMethods.js | 1 - .../src/utils/constants.js | 2 +- packages/fes-template-h5/.fes.js | 3 - packages/fes-template-h5/src/pages/index.vue | 4 +- packages/fes-template/README.md | 9 + packages/fes-template/src/pages/index.vue | 2 +- packages/fes/.fatherrc.js | 2 +- packages/fes/src/cli.js | 1 + packages/fes/src/forkedDev.js | 1 + yarn.lock | 4412 +++++------------ 48 files changed, 2267 insertions(+), 3727 deletions(-) create mode 100644 packages/fes-compiler/src/service/babelRegister.js create mode 100644 packages/fes-preset-built-in/src/plugins/commands/build/build.js rename packages/fes-preset-built-in/src/{utils => plugins/commands}/buildDevUtils.js (58%) create mode 100644 packages/fes-preset-built-in/src/plugins/commands/dev/devServer.js create mode 100644 packages/fes-preset-built-in/src/plugins/commands/webpackConfig/css.js create mode 100644 packages/fes-preset-built-in/src/plugins/commands/webpackConfig/define.js create mode 100644 packages/fes-preset-built-in/src/plugins/commands/webpackConfig/getBableOpts.js create mode 100644 packages/fes-preset-built-in/src/plugins/commands/webpackConfig/getConfig.js create mode 100644 packages/fes-preset-built-in/src/plugins/commands/webpackConfig/html.js rename packages/fes-preset-built-in/src/plugins/{features => commands/webpackConfig}/index-default.html (100%) create mode 100644 packages/fes-preset-built-in/src/plugins/commands/webpackConfig/minimizer.js create mode 100644 packages/fes-preset-built-in/src/plugins/commands/webpackConfig/vue.js delete mode 100644 packages/fes-preset-built-in/src/plugins/features/chunks.js delete mode 100644 packages/fes-preset-built-in/src/plugins/features/cssnano.js delete mode 100644 packages/fes-preset-built-in/src/plugins/features/hash.js delete mode 100644 packages/fes-preset-built-in/src/plugins/features/imageMinimizer.js delete mode 100644 packages/fes-preset-built-in/src/plugins/features/styleLoader.js diff --git a/package.json b/package.json index bcea4002..2008d6eb 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "strong" ], "dependencies": { - "lerna": "^3.18.4" + "lerna": "^3.22.1" }, "devDependencies": { "@commitlint/cli": "^11.0.0", @@ -38,7 +38,7 @@ "commitizen": "^4.2.1", "cz-conventional-changelog": "^3.3.0", "esbuild-loader": "^2.7.0", - "father-build": "^1.18.5", + "father-build": "^1.19.1", "husky": "^4.3.0", "lint-staged": "^10.4.0", "vuepress": "^2.0.0-alpha.18" diff --git a/packages/fes-compiler/package.json b/packages/fes-compiler/package.json index 54cd1aec..f2ec7324 100644 --- a/packages/fes-compiler/package.json +++ b/packages/fes-compiler/package.json @@ -24,13 +24,13 @@ "access": "public" }, "dependencies": { - "@babel/register": "^7.12.1", - "@umijs/babel-preset-umi": "3.3.3", + "@babel/register": "^7.12.13", + "@babel/preset-env": "^7.12.13", "@umijs/utils": "3.3.3", "dotenv": "8.2.0", "joi": "17.3.0", "readline": "^1.3.0", "set-value": "3.0.2", - "tapable": "2.0.0" + "tapable": "^2.2.0" } } diff --git a/packages/fes-compiler/src/service/babelRegister.js b/packages/fes-compiler/src/service/babelRegister.js new file mode 100644 index 00000000..a64f328d --- /dev/null +++ b/packages/fes-compiler/src/service/babelRegister.js @@ -0,0 +1,43 @@ +import { + lodash, + winPath +} from '@umijs/utils'; + + +export default class BabelRegister { + only = {}; + + setOnlyMap({ + key, + value + }) { + this.only[key] = value; + this.register(); + } + + register() { + const only = lodash.uniq( + Object.keys(this.only) + .reduce((memo, key) => memo.concat(this.only[key]), []) + .map(winPath) + ); + require('@babel/register')({ + presets: [ + [ + require.resolve('@babel/preset-env'), + { + targets: { + node: 'current' + }, + modules: 'commonjs' + } + ] + ], + ignore: [/node_modules/], + only, + extensions: ['.jsx', '.js', '.ts', '.tsx'], + babelrc: false, + cache: false + }); + } +} diff --git a/packages/fes-compiler/src/service/index.js b/packages/fes-compiler/src/service/index.js index f3e12dd4..50c2a34f 100644 --- a/packages/fes-compiler/src/service/index.js +++ b/packages/fes-compiler/src/service/index.js @@ -3,7 +3,8 @@ import { EventEmitter } from 'events'; import assert from 'assert'; import { AsyncSeriesWaterfallHook } from 'tapable'; import { existsSync } from 'fs'; -import { BabelRegister, lodash } from '@umijs/utils'; +import { lodash } from '@umijs/utils'; +import BabelRegister from './babelRegister'; import { resolvePresets, pathToObj, resolvePlugins } from './utils/pluginUtils'; import loadDotEnv from './utils/loadDotEnv'; import isPromise from './utils/isPromise'; @@ -146,6 +147,9 @@ export default class Service extends EventEmitter { const localPath = `${basePath}.local`; loadDotEnv(basePath); loadDotEnv(localPath); + if (process.env.FES_ENV) { + loadDotEnv(`${basePath}.${process.env.FES_ENV}`); + } } async init() { diff --git a/packages/fes-preset-built-in/package.json b/packages/fes-preset-built-in/package.json index 6c871441..d1418bfb 100644 --- a/packages/fes-preset-built-in/package.json +++ b/packages/fes-preset-built-in/package.json @@ -25,19 +25,46 @@ "access": "public" }, "dependencies": { - "@umijs/bundler-webpack": "3.3.3", - "@umijs/server": "3.3.3", + "@babel/core": "^7.12.13", + "@babel/preset-env": "^7.12.13", + "@babel/plugin-proposal-export-default-from": "^7.12.13", + "@babel/plugin-proposal-pipeline-operator": "^7.12.13", + "@babel/plugin-proposal-do-expressions": "^7.12.13", + "@babel/plugin-proposal-function-bind": "^7.12.13", + "@babel/plugin-transform-runtime": "^7.12.13", "@umijs/utils": "3.3.3", - "@vue/babel-plugin-jsx": "^1.0.0-rc.5", + "@vue/babel-plugin-jsx": "^1.0.2", "@vue/compiler-sfc": "^3.0.4", - "@vue/preload-webpack-plugin": "1.1.2", "@webank/fes-compiler": "^2.0.0-alpha.2", - "cliui": "6.0.0", - "html-webpack-plugin": "^3.2.0", - "html-webpack-tags-plugin": "2.0.17", + "babel-loader": "^8.2.2", + "core-js": "^3.8.3", + "cliui": "7.0.4", + "html-webpack-plugin": "^5.0.0", + "html-webpack-tags-plugin": "^3.0.0", "vue-loader": "^16.1.2", - "webpack-bundle-analyzer": "4.3.0", + "webpackbar": "^5.0.0-3", + "@soda/friendly-errors-webpack-plugin": "^1.8.0", + "webpack-bundle-analyzer": "^4.4.0", + "webpack-dev-server": "^3.11.2", "babel-plugin-import": "1.13.3", - "hard-source-webpack-plugin": "0.13.1" + "hard-source-webpack-plugin": "0.13.1", + "file-loader": "^6.2.0", + "url-loader": "^4.1.1", + "raw-loader": "^4.0.2", + "css-loader": "^5.0.1", + "style-loader": "^2.0.0", + "mini-css-extract-plugin": "^1.3.5", + "css-minimizer-webpack-plugin": "^1.2.0", + "less": "3.9.0", + "less-loader": "^8.0.0", + "autoprefixer": "^10.2.4", + "postcss-loader": "^4.2.0", + "postcss": "^8.2.4", + "postcss-flexbugs-fixes": "^5.0.2", + "postcss-safe-parser": "^5.0.2", + "copy-webpack-plugin": "^7.0.0", + "webpack-chain": "^6.5.1", + "webpack": "^5.21.0", + "deepmerge": "^4.2.2" } } diff --git a/packages/fes-preset-built-in/src/index.js b/packages/fes-preset-built-in/src/index.js index 68f57d92..a30157f4 100644 --- a/packages/fes-preset-built-in/src/index.js +++ b/packages/fes-preset-built-in/src/index.js @@ -17,9 +17,7 @@ export default function () { require.resolve('./plugins/features/base'), require.resolve('./plugins/features/babelPluginImport'), require.resolve('./plugins/features/chainWebpack'), - require.resolve('./plugins/features/chunks'), require.resolve('./plugins/features/cssLoader'), - require.resolve('./plugins/features/cssnano'), require.resolve('./plugins/features/copy'), require.resolve('./plugins/features/define'), require.resolve('./plugins/features/devScripts'), @@ -29,22 +27,19 @@ export default function () { require.resolve('./plugins/features/extraBabelPlugins'), require.resolve('./plugins/features/extraBabelPresets'), require.resolve('./plugins/features/extraPostCSSPlugins'), - require.resolve('./plugins/features/hash'), require.resolve('./plugins/features/html'), require.resolve('./plugins/features/inlineLimit'), - require.resolve('./plugins/features/imageMinimizer'), require.resolve('./plugins/features/lessLoader'), require.resolve('./plugins/features/mountElementId'), - require.resolve('./plugins/features/nodeModulesTransform'), require.resolve('./plugins/features/outputPath'), require.resolve('./plugins/features/plugins'), require.resolve('./plugins/features/postcssLoader'), require.resolve('./plugins/features/proxy'), require.resolve('./plugins/features/publicPath'), - require.resolve('./plugins/features/styleLoader'), require.resolve('./plugins/features/singular'), require.resolve('./plugins/features/targets'), require.resolve('./plugins/features/terserOptions'), + require.resolve('./plugins/features/nodeModulesTransform'), require.resolve('./plugins/features/vueLoader'), require.resolve('./plugins/features/hardSource'), diff --git a/packages/fes-preset-built-in/src/plugins/commands/build/build.js b/packages/fes-preset-built-in/src/plugins/commands/build/build.js new file mode 100644 index 00000000..fceedf50 --- /dev/null +++ b/packages/fes-preset-built-in/src/plugins/commands/build/build.js @@ -0,0 +1,19 @@ +import webpack from 'webpack'; + +export async function build({ + bundleConfig +}) { + return new Promise((resolve, reject) => { + const compiler = webpack(bundleConfig); + compiler.run((err, stats) => { + if (err || stats.hasErrors()) { + try { + console.log(stats.toString('errors-only')); + } catch (e) {} + console.error(err); + return reject(new Error('build failed')); + } + resolve({ stats }); + }); + }); +} diff --git a/packages/fes-preset-built-in/src/plugins/commands/build/index.js b/packages/fes-preset-built-in/src/plugins/commands/build/index.js index e6236bfd..95533783 100644 --- a/packages/fes-preset-built-in/src/plugins/commands/build/index.js +++ b/packages/fes-preset-built-in/src/plugins/commands/build/index.js @@ -5,8 +5,9 @@ import { cleanTmpPathExceptCache, getBundleAndConfigs, printFileSizes -} from '../../../utils/buildDevUtils'; +} from '../buildDevUtils'; import generateFiles from '../../../utils/generateFiles'; +import { build } from './build'; const logger = new Logger('fes:plugin-built-in'); @@ -28,11 +29,7 @@ export default function (api) { await generateFiles({ api, watch: false }); // build - const { - bundler, - bundleConfigs, - bundleImplementor - } = await getBundleAndConfigs({ api }); + const { bundleConfig } = await getBundleAndConfigs({ api }); try { // clear output path before exec build if (process.env.CLEAR_OUTPUT !== 'none') { @@ -42,10 +39,7 @@ export default function (api) { } } - const { stats } = await bundler.build({ - bundleConfigs, - bundleImplementor - }); + const { stats } = await build({ bundleConfig }); if (process.env.RM_TMPDIR !== 'none') { rimraf.sync(paths.absTmpPath); } diff --git a/packages/fes-preset-built-in/src/utils/buildDevUtils.js b/packages/fes-preset-built-in/src/plugins/commands/buildDevUtils.js similarity index 58% rename from packages/fes-preset-built-in/src/utils/buildDevUtils.js rename to packages/fes-preset-built-in/src/plugins/commands/buildDevUtils.js index 4dac8a10..5f99c32a 100644 --- a/packages/fes-preset-built-in/src/utils/buildDevUtils.js +++ b/packages/fes-preset-built-in/src/plugins/commands/buildDevUtils.js @@ -1,109 +1,70 @@ -import { Bundler as DefaultBundler } from '@umijs/bundler-webpack'; import { join, resolve } from 'path'; import { existsSync, readdirSync, readFileSync } from 'fs'; import { rimraf, chalk } from '@umijs/utils'; import zlib from 'zlib'; +import getConfig from './webpackConfig/getConfig'; export async function getBundleAndConfigs({ - api, - port + api }) { - // bundler - const Bundler = await api.applyPlugins({ - type: api.ApplyPluginsType.modify, - key: 'modifyBundler', - initialValue: DefaultBundler - }); - - const bundleImplementor = await api.applyPlugins({ - key: 'modifyBundleImplementor', - type: api.ApplyPluginsType.modify, - initialValue: undefined - }); - - const bundler = new Bundler({ - cwd: api.cwd, - config: api.config - }); - const bundlerArgs = { - env: api.env, - bundler: { id: Bundler.id, version: Bundler.version } - }; - // get config - async function getConfig({ type }) { - const env = api.env === 'production' ? 'production' : 'development'; - const getConfigOpts = await api.applyPlugins({ - type: api.ApplyPluginsType.modify, - key: 'modifyBundleConfigOpts', - initialValue: { - env, - type, - port, - hot: process.env.HMR !== 'none', - entry: { - fes: join(api.paths.absTmpPath, 'fes.js') - }, - // @ts-ignore - bundleImplementor, - async modifyBabelOpts(opts) { - return api.applyPlugins({ - type: api.ApplyPluginsType.modify, - key: 'modifyBabelOpts', - initialValue: opts - }); - }, - async modifyBabelPresetOpts(opts) { - return api.applyPlugins({ - type: api.ApplyPluginsType.modify, - key: 'modifyBabelPresetOpts', - initialValue: opts - }); - }, - async chainWebpack(webpackConfig, opts) { - return api.applyPlugins({ - type: api.ApplyPluginsType.modify, - key: 'chainWebpack', - initialValue: webpackConfig, - args: { - ...opts - } - }); - } - }, - args: { - ...bundlerArgs, - type - } - }); - return api.applyPlugins({ - type: api.ApplyPluginsType.modify, - key: 'modifyBundleConfig', - initialValue: await bundler.getConfig(getConfigOpts), - args: { - ...bundlerArgs, - type - } - }); - } - - const bundleConfigs = await api.applyPlugins({ + const env = api.env === 'production' ? 'production' : 'development'; + const getConfigOpts = await api.applyPlugins({ type: api.ApplyPluginsType.modify, - key: 'modifyBundleConfigs', - initialValue: [await getConfig({ type: 'csr' })].filter( - Boolean - ), + key: 'modifyBundleConfigOpts', + initialValue: { + cwd: api.paths.cwd, + config: api.config, + env, + entry: { + index: join(api.paths.absTmpPath, 'fes.js') + }, + // @ts-ignore + async modifyBabelOpts(opts) { + return api.applyPlugins({ + type: api.ApplyPluginsType.modify, + key: 'modifyBabelOpts', + initialValue: opts + }); + }, + async modifyBabelPresetOpts(opts) { + return api.applyPlugins({ + type: api.ApplyPluginsType.modify, + key: 'modifyBabelPresetOpts', + initialValue: opts + }); + }, + async chainWebpack(webpackConfig, opts) { + return api.applyPlugins({ + type: api.ApplyPluginsType.modify, + key: 'chainWebpack', + initialValue: webpackConfig, + args: { + ...opts + } + }); + }, + async headScripts() { + return api.applyPlugins({ + key: 'addHTMLHeadScripts', + type: api.ApplyPluginsType.add, + initialState: [] + }); + } + }, args: { - ...bundlerArgs, - getConfig } }); - return { - bundleImplementor, - bundler, - bundleConfigs - }; + const bundleConfig = await api.applyPlugins({ + type: api.ApplyPluginsType.modify, + key: 'modifyBundleConfig', + initialValue: await getConfig(getConfigOpts), + args: { + } + }); + + return { bundleConfig }; } export function cleanTmpPathExceptCache({ @@ -219,7 +180,7 @@ export function printFileSizes(stats, dir) { ); console.log( chalk.yellow( - 'Consider reducing it with code splitting: https://umijs.org/docs/load-on-demand' + 'Consider reducing it with code splitting' ) ); console.log( diff --git a/packages/fes-preset-built-in/src/plugins/commands/dev/devServer.js b/packages/fes-preset-built-in/src/plugins/commands/dev/devServer.js new file mode 100644 index 00000000..74523e06 --- /dev/null +++ b/packages/fes-preset-built-in/src/plugins/commands/dev/devServer.js @@ -0,0 +1,46 @@ +import WebpackDevServer from 'webpack-dev-server'; +import webpack from 'webpack'; + + +export function startDevServer({ + webpackConfig, + host, + port, + beforeMiddlewares, + afterMiddlewares, + customerDevServerConfig +}) { + const options = { + contentBase: webpackConfig.output.path, + hot: true, + host, + compress: true, + noInfo: true, + clientLogLevel: 'silent', + stats: 'errors-only', + before: (app) => { + beforeMiddlewares.forEach((middleware) => { + app.use(middleware); + }); + }, + after: (app) => { + afterMiddlewares.forEach((middleware) => { + app.use(middleware); + }); + }, + headers: { + 'access-control-allow-origin': '*' + }, + ...(customerDevServerConfig || {}) + }; + WebpackDevServer.addDevServerEntrypoints(webpackConfig, options); + const compiler = webpack(webpackConfig); + const server = new WebpackDevServer(compiler, options); + + server.listen(port, host, (err) => { + if (err) { + console.error(err); + } + }); + return server; +} diff --git a/packages/fes-preset-built-in/src/plugins/commands/dev/index.js b/packages/fes-preset-built-in/src/plugins/commands/dev/index.js index d7529aec..b90a2039 100644 --- a/packages/fes-preset-built-in/src/plugins/commands/dev/index.js +++ b/packages/fes-preset-built-in/src/plugins/commands/dev/index.js @@ -1,12 +1,12 @@ -import { Server } from '@umijs/server'; import { delay } from '@umijs/utils'; import assert from 'assert'; import { cleanTmpPathExceptCache, getBundleAndConfigs -} from '../../../utils/buildDevUtils'; +} from '../buildDevUtils'; import generateFiles from '../../../utils/generateFiles'; import { watchPkg } from './watchPkg'; +import { startDevServer } from './devServer'; export default (api) => { const { @@ -24,8 +24,7 @@ export default (api) => { for (const unwatch of unwatchs) { unwatch(); } - // eslint-disable-next-line - server?.listeningApp?.close(); + server?.close(); } api.registerCommand({ @@ -37,15 +36,12 @@ export default (api) => { port: defaultPort ? parseInt(String(defaultPort), 10) : 8000 }); hostname = process.env.HOST || api.config.devServer?.host || '0.0.0.0'; - console.log(chalk.cyan('Starting the development server...')); + console.log(chalk.cyan(`Starting the development server http://${hostname}:${port} ...`)); process.send({ type: 'UPDATE_PORT', port }); - // enable https, HTTP/2 by default when using --https - const isHTTPS = process.env.HTTPS || args.https; - cleanTmpPathExceptCache({ absTmpPath: paths.absTmpPath }); @@ -141,18 +137,7 @@ export default (api) => { await delay(500); // dev - const { - bundler, - bundleConfigs, - bundleImplementor - } = await getBundleAndConfigs({ - api, - port - }); - const opts = bundler.setupDevServerOpts({ - bundleConfigs, - bundleImplementor - }); + const { bundleConfig } = await getBundleAndConfigs({ api }); const beforeMiddlewares = await api.applyPlugins({ key: 'addBeforeMiddlewares', @@ -166,25 +151,16 @@ export default (api) => { initialValue: [], args: {} }); - - server = new Server({ - ...opts, - compress: true, - https: !!isHTTPS, - headers: { - 'access-control-allow-origin': '*' - }, + server = startDevServer({ + webpackConfig: bundleConfig, + host: hostname, + port, proxy: api.config.proxy, beforeMiddlewares, afterMiddlewares: [...middlewares], - ...(api.config.devServer || {}) - }); - const listenRet = await server.listen({ - port, - hostname + customerDevServerConfig: api.config.devServer }); return { - ...listenRet, destroy }; } diff --git a/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/css.js b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/css.js new file mode 100644 index 00000000..4752ba07 --- /dev/null +++ b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/css.js @@ -0,0 +1,104 @@ +// css less post-css mini-css css 压缩 +// extraPostCSSPlugins +// postcssLoader +// lessLoader +// css-loader +// 支持 热加载 +// 性能优化 +// css 压缩 https://github.com/webpack-contrib/css-minimizer-webpack-plugin +// 根据 entry 进行代码块拆分 +// 根据 entry 将文件输出到不同的文件夹 + +import deepmerge from 'deepmerge'; + +function createRules({ + isDev, + webpackConfig, + config, + lang, + test, + loader, + options, + browserslist +}) { + const rule = webpackConfig.module.rule(lang).test(test); + + if (isDev) { + rule.use('extra-css-loader') + .loader(require.resolve('style-loader')) + .options({ + }); + } else { + rule.use('extra-css-loader') + .loader(require('mini-css-extract-plugin').loader) + .options({ + }); + } + + rule.use('css-loader') + .loader(require.resolve('css-loader')) + .options({ + ...config.cssLoader + }); + + rule.use('postcss-loader') + .loader(require.resolve('postcss-loader')) + .options(deepmerge({ + postcssOptions: () => ({ + plugins: [ + // https://github.com/luisrudge/postcss-flexbugs-fixes + require('postcss-flexbugs-fixes'), + require('postcss-safe-parser'), + [require('autoprefixer'), { ...config.autoprefixer, overrideBrowserslist: browserslist }], + ...(config.extraPostCSSPlugins ? config.extraPostCSSPlugins : []) + ] + }) + }, config.postcssLoader || {})); + + if (loader) { + rule.use(loader) + .loader(require.resolve(loader)) + .options(options); + } +} + +export default function createCssWebpackConfig({ + isDev, + config, + webpackConfig, + browserslist +}) { + createRules({ + isDev, + webpackConfig, + config, + lang: 'css', + test: /\.css$/, + browserslist + }); + + createRules({ + isDev, + webpackConfig, + config, + lang: 'less', + test: /\.less$/, + loader: 'less-loader', + options: config.lessLoader || {}, + browserslist + }); + + webpackConfig.plugin('extra-css') + .use(require.resolve('mini-css-extract-plugin'), [{ + filename: isDev ? '[name].css' : '[name].[contenthash:8].css', + chunkFilename: isDev ? '[id].css' : '[id].[contenthash:8].css' + }]); + + if (!isDev) { + webpackConfig.optimization + .minimizer('css') + .use(require.resolve('css-minimizer-webpack-plugin'), [{ + sourceMap: config.devtool !== false + }]); + } +} diff --git a/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/define.js b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/define.js new file mode 100644 index 00000000..476741aa --- /dev/null +++ b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/define.js @@ -0,0 +1,47 @@ +import webpack from 'webpack'; + +const prefixRE = /^FES_APP_/; + +const ENV_SHOULD_PASS = ['NODE_ENV', 'HMR', 'SOCKET_SERVER', 'ERROR_OVERLAY']; + +function resolveDefine(opts = {}) { + const env = {}; + Object.keys(process.env).forEach((key) => { + if (prefixRE.test(key) || ENV_SHOULD_PASS.includes(key)) { + env[key] = process.env[key]; + } + }); + + for (const key in env) { + if (Object.prototype.hasOwnProperty.call(env, key)) { + env[key] = JSON.stringify(env[key]); + } + } + + const define = { + __VUE_OPTIONS_API__: true, + __VUE_PROD_DEVTOOLS__: false, + ...opts.define + }; + + for (const key in define) { + if (Object.prototype.hasOwnProperty.call(define, key)) { + define[key] = JSON.stringify(opts.define[key]); + } + } + + return { + 'process.env': env, + ...define + }; +} + +export default function createDefineWebpackConfig({ + config, + webpackConfig +}) { + webpackConfig.plugin('define') + .use(webpack.DefinePlugin, [ + resolveDefine({ define: config.define }) + ]); +} diff --git a/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/getBableOpts.js b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/getBableOpts.js new file mode 100644 index 00000000..22b7cac8 --- /dev/null +++ b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/getBableOpts.js @@ -0,0 +1,84 @@ +import { + winPath +} from '@umijs/utils'; + +function getBabelOpts({ + cwd, + targets, + presetOpts +}) { + const presets = [ + [ + require.resolve('@babel/preset-env'), + { + targets, + useBuiltIns: 'usage', + corejs: { + version: 3, + proposals: true + }, + modules: false + } + ] + ]; + const plugins = [ + require('@babel/plugin-proposal-export-default-from').default, + [ + require('@babel/plugin-proposal-pipeline-operator').default, + { + proposal: 'minimal' + } + ], + require('@babel/plugin-proposal-do-expressions').default, + require('@babel/plugin-proposal-function-bind').default, + [ + require.resolve('@babel/plugin-transform-runtime'), + { + useESModules: true, + ...presetOpts.transformRuntime + } + ], + ...(presetOpts.import + ? presetOpts.import.map(importOpts => [ + require.resolve('babel-plugin-import'), + importOpts, + importOpts.libraryName + ]) + : []), + require.resolve('@vue/babel-plugin-jsx') + ]; + return { + babelrc: false, + cacheDirectory: process.env.BABEL_CACHE !== 'none' ? winPath(`${cwd}/.cache/babel-loader`) : false, + presets, + plugins, + overrides: [{ + test: [/[\\/]node_modules[\\/]/, /\.fes/], + sourceType: 'unambiguous' + }] + }; +} + + +export default async ({ + cwd, + modifyBabelOpts, + modifyBabelPresetOpts, + targets +}) => { + let presetOpts = { + transformRuntime: {} + }; + if (modifyBabelPresetOpts) { + presetOpts = await modifyBabelPresetOpts(presetOpts); + } + let babelOpts = getBabelOpts({ + cwd, + presetOpts, + targets + }); + if (modifyBabelOpts) { + babelOpts = await modifyBabelOpts(babelOpts); + } + return babelOpts; +}; diff --git a/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/getConfig.js b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/getConfig.js new file mode 100644 index 00000000..fbe301ca --- /dev/null +++ b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/getConfig.js @@ -0,0 +1,305 @@ +import { join } from 'path'; +import { existsSync } from 'fs'; +import Config from 'webpack-chain'; +import webpack from 'webpack'; +import createCssWebpackConfig from './css'; +import getBableOpts from './getBableOpts'; +import createVueWebpackConfig from './vue'; +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', + 'vue-router', + 'ant-design-vue', + 'core-js', + 'echarts', + '@babel/runtime', + 'lodash', + 'webpack-dev-server', + 'ansi-html', + 'html-entities' +]; + +function genTranspileDepRegex(exclude) { + exclude = exclude.concat(DEFAULT_EXCLUDE_NODE_MODULES); + const deps = exclude.map((dep) => { + if (typeof dep === 'string') { + const depPath = join('node_modules', dep, '/'); + return /^win/.test(require('os').platform()) ? depPath.replace(/\\/g, '\\\\') : depPath; + } if (dep instanceof RegExp) { + return dep.source; + } + + throw new Error('exclude only accepts an array of string or regular expressions'); + }); + return deps.length ? new RegExp(deps.join('|')) : null; +} + + +export default async function getConfig({ + cwd, + config, + env, + entry = {}, + modifyBabelOpts, + modifyBabelPresetOpts, + chainWebpack, + headScripts +}) { + const isDev = env === 'development'; + const isProd = env === 'production'; + const webpackConfig = new Config(); + const absoluteOutput = join(cwd, config.outputPath || 'dist'); + + webpackConfig.mode(env); + webpackConfig.stats('verbose'); + webpackConfig.externals(config.externals || {}); + webpackConfig.devtool(isDev ? (config.devtool || 'cheap-module-source-map') : config.devtool); + + // --------------- entry ----------- + // Feature 公共模块 vue vue-router 处理 dependOn ? + Object.keys(entry).forEach((key) => { + webpackConfig.entry(key).add(entry[key]).end(); + }); + + // --------------- output ----------- + webpackConfig.output + .path(absoluteOutput) + .publicPath(config.publicPath || '') + .filename('[name].[contenthash:8].js') + .chunkFilename('[name].[contenthash:8].chunk.js'); + + // --------------- resolve ----------- + webpackConfig.resolve.extensions.merge(['.mjs', '.js', '.jsx', '.vue', '.json', '.wasm']); + + if (config.alias) { + Object.keys(config.alias).forEach((key) => { + webpackConfig.resolve.alias + .set(key, config.alias[key]); + }); + } + + // --------------- module ----------- + webpackConfig.module + .rule('image') + .test(/\.(png|jpe?g|gif|webp|ico)(\?.*)?$/) + .use('url-loader') + .loader(require.resolve('url-loader')) + .options({ + limit: config.inlineLimit || 8192, + esModule: false, + fallback: { + loader: require.resolve('file-loader'), + options: { + name: 'static/[name].[hash:8].[ext]', + esModule: false + } + } + }); + + webpackConfig.module + .rule('svg') + .test(/\.(svg)(\?.*)?$/) + .use('file-loader') + .loader(require.resolve('file-loader')) + .options({ + name: 'static/[name].[hash:8].[ext]', + esModule: false + }); + + webpackConfig.module + .rule('fonts') + .test(/\.(eot|woff|woff2|ttf)(\?.*)?$/) + .use('file-loader') + .loader(require.resolve('file-loader')) + .options({ + name: 'static/[name].[hash:8].[ext]', + esModule: false + }); + + webpackConfig.module + .rule('raw') + .test(/\.(txt|text|md)$/) + .use('raw-loader') + .loader(require.resolve('raw-loader')) + .options({ + esModule: false + }); + + const { targets, browserslist } = getTargetsAndBrowsersList({ config }); + const babelOpts = await getBableOpts({ + cwd, + modifyBabelOpts, + modifyBabelPresetOpts, + targets + }); + + // --------------- js ----------- + webpackConfig.module + .rule('js') + .test(/\.(js|mjs|jsx)$/) + .exclude.add((filepath) => { + // always transpile js in vue files + if (/\.vue\.jsx?$/.test(filepath)) { + return false; + } + // Don't transpile node_modules + return /node_modules/.test(filepath); + }).end() + .use('babel-loader') + .loader(require.resolve('babel-loader')) + .options(babelOpts); + + // 为了避免第三方依赖包编译不充分导致线上问题,默认对 node_modules 也进行全编译 + const transpileDepRegex = genTranspileDepRegex(config.nodeModulesTransform.exclude); + webpackConfig.module + .rule('js-in-node_modules') + .test(/\.(js|mjs)$/) + .include.add(/node_modules/).end() + .exclude.add((filepath) => { + if (transpileDepRegex && transpileDepRegex.test(filepath)) { + return true; + } + + return false; + }).end() + .use('babel-loader') + .loader(require.resolve('babel-loader')) + .options(babelOpts); + + // --------------- css ----------- + createCssWebpackConfig({ + isDev, + config, + webpackConfig, + browserslist + }); + + // --------------- vue ----------- + createVueWebpackConfig({ + config, + webpackConfig + }); + + // --------------- html ----------- + const { publicCopyIgnore } = await createHtmlWebpackConfig({ + cwd, + config, + webpackConfig, + headScripts, + isProd + }); + + // --------------- copy ----------- + const copyPatterns = [existsSync(join(cwd, 'public')) && { + from: join(cwd, 'public'), + filter: (resourcePath) => { + if (resourcePath.indexOf('.DS_Store') !== -1) { + return false; + } + if (publicCopyIgnore.includes(resourcePath)) { + return false; + } + return true; + }, + to: absoluteOutput + }, ...((config.copy || []).map((item) => { + if (typeof item === 'string') { + return { + from: join(cwd, item.from), + to: absoluteOutput + }; + } + return { + from: join(cwd, item.from), + to: join(absoluteOutput, item.to) + }; + }))].filter(Boolean); + // const publicCopyIgnore = ['.DS_Store']; + webpackConfig + .plugin('copy') + .use(require.resolve('copy-webpack-plugin'), [{ + patterns: copyPatterns + }]); + + // --------------- define ----------- + createDefineWebpackConfig({ + config, + webpackConfig + }); + + // --------------- 分包 ----------- + if (isProd) { + webpackConfig.optimization.splitChunks({ + cacheGroups: { + defaultVendors: { + name: 'chunk-vendors', + test: /[\\/]node_modules[\\/]/, + priority: -10, + chunks: 'initial' + }, + common: { + name: 'chunk-common', + minChunks: 2, + priority: -20, + chunks: 'initial', + reuseExistingChunk: true + } + } + }); + } + + // --------------- 压缩 ----------- + createMinimizerWebpackConfig({ + isProd, + config, + webpackConfig + }); + + // --------------- 构建输出 ---------- + webpackConfig + .plugin('progress') + .use(require.resolve('webpackbar')); + + webpackConfig + .plugin('friendly-errors') + .use(require('@soda/friendly-errors-webpack-plugin')); + + // --------------- chainwebpack ----------- + if (chainWebpack) { + await chainWebpack(webpackConfig, { + webpack + }); + } + // 用户配置的 chainWebpack 优先级最高 + if (config.chainWebpack) { + await config.chainWebpack(webpackConfig, { + env, + webpack + }); + } + + return webpackConfig.toConfig(); +} diff --git a/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/html.js b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/html.js new file mode 100644 index 00000000..f96d5023 --- /dev/null +++ b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/html.js @@ -0,0 +1,63 @@ +import { join, resolve } from 'path'; +import { existsSync } from 'fs'; + +export default async function createHtmlWebpackConfig({ + cwd, + config, + webpackConfig, + headScripts, + isProd +}) { + const htmlOptions = { + filename: '[name].html', + ...config.html.options + }; + + + if (isProd) { + Object.assign(htmlOptions, { + minify: { + removeComments: true, + collapseWhitespace: true, + collapseBooleanAttributes: true, + removeScriptTypeAttributes: true + // more options: + // https://github.com/kangax/html-minifier#options-quick-reference + } + }); + } + + const multiPageConfig = config.html.pages; + const htmlPath = join(cwd, 'public/index.html'); + const defaultHtmlPath = resolve(__dirname, 'index-default.html'); + const publicCopyIgnore = []; + + if (!multiPageConfig) { + // default, single page setup. + htmlOptions.template = existsSync(htmlPath) + ? htmlPath + : defaultHtmlPath; + + publicCopyIgnore.push(htmlOptions.template); + webpackConfig + .plugin('html') + .use(require.resolve('html-webpack-plugin'), [htmlOptions]); + } else { + // TODO 支持多页 + } + + if (headScripts) { + const headScriptsMap = await headScripts(); + webpackConfig + .plugin('html-tags') + .use(require.resolve('html-webpack-tags-plugin'), [{ + append: false, + scripts: headScriptsMap.map(script => ({ + path: script.src + })) + }]); + } + return { + publicCopyIgnore + }; +} diff --git a/packages/fes-preset-built-in/src/plugins/features/index-default.html b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/index-default.html similarity index 100% rename from packages/fes-preset-built-in/src/plugins/features/index-default.html rename to packages/fes-preset-built-in/src/plugins/commands/webpackConfig/index-default.html diff --git a/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/minimizer.js b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/minimizer.js new file mode 100644 index 00000000..308fe01d --- /dev/null +++ b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/minimizer.js @@ -0,0 +1,62 @@ +import deepmerge from 'deepmerge'; + +const defaultTerserOptions = { + compress: { + // turn off flags with small gains to speed up minification + arrows: false, + collapse_vars: false, // 0.3kb + comparisons: false, + computed_props: false, + hoist_funs: false, + hoist_props: false, + hoist_vars: false, + inline: false, + loops: false, + negate_iife: false, + properties: false, + reduce_funcs: false, + reduce_vars: false, + switches: false, + toplevel: false, + typeofs: false, + + // a few flags with noticeable gains/speed ratio + // numbers based on out of the box vendor bundle + booleans: true, // 0.7kb + if_return: true, // 0.4kb + sequences: true, // 0.7kb + unused: true, // 2.3kb + + // required features to drop conditional branches + conditionals: true, + dead_code: true, + evaluate: true + }, + mangle: { + safari10: true + } +}; + +const terserOptions = config => ({ + terserOptions: deepmerge( + defaultTerserOptions, + config.terserOptions || {} + ), + extractComments: false +}); + + +export default function createMinimizerWebpackConfig({ + isProd, + config, + webpackConfig +}) { + if (isProd) { + webpackConfig.optimization + .minimizer('terser') + .use(require.resolve('terser-webpack-plugin'), [terserOptions(config)]); + } + if (process.env.FES_ENV === 'test') { + webpackConfig.optimization.minimize(false); + } +} diff --git a/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/vue.js b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/vue.js new file mode 100644 index 00000000..549a940e --- /dev/null +++ b/packages/fes-preset-built-in/src/plugins/commands/webpackConfig/vue.js @@ -0,0 +1,28 @@ +// import webpack from 'webpack'; + +export default function createVueWebpackConfig({ + config, + webpackConfig +}) { + webpackConfig.module + .rule('vue') + .test(/\.vue$/) + .use('vue-loader') + .loader(require.resolve('vue-loader')) + .options({ + babelParserPlugins: ['jsx', 'classProperties', 'decorators-legacy'], + ...(config.vueLoader || {}) + }) + .end(); + + webpackConfig + .plugin('vue-loader') + .use(require('vue-loader').VueLoaderPlugin); + + // webpackConfig + // .plugin('feature-flags') + // .use(webpack.DefinePlugin, [{ + // __VUE_OPTIONS_API__: 'true', + // __VUE_PROD_DEVTOOLS__: 'false' + // }]); +} diff --git a/packages/fes-preset-built-in/src/plugins/features/alias.js b/packages/fes-preset-built-in/src/plugins/features/alias.js index c94709c0..85b531d4 100644 --- a/packages/fes-preset-built-in/src/plugins/features/alias.js +++ b/packages/fes-preset-built-in/src/plugins/features/alias.js @@ -1,8 +1,5 @@ -import { dirname } from 'path'; -import { winPath, resolve } from '@umijs/utils'; - export default (api) => { - const { paths, pkg, cwd } = api; + const { paths } = api; api.describe({ key: 'alias', @@ -15,50 +12,11 @@ export default (api) => { } }); - function getUserLibDir({ library }) { - if ( - (pkg.dependencies && pkg.dependencies[library]) - || (pkg.devDependencies && pkg.devDependencies[library]) - // egg project using `clientDependencies` in ali tnpm - || (pkg.clientDependencies && pkg.clientDependencies[library]) - ) { - return winPath( - dirname( - // 通过 resolve 往上找,可支持 lerna 仓库 - // lerna 仓库如果用 yarn workspace 的依赖不一定在 node_modules,可能被提到根目录,并且没有 link - resolve.sync(`${library}/package.json`, { - basedir: cwd - }) - ) - ); - } - return null; - } - - // 另一种实现方式: - // 提供 projectFirstLibraries 的配置方式,但是不通用,先放插件层实现 api.chainWebpack(async (memo) => { - const libraries = await api.applyPlugins({ - key: 'addProjectFirstLibraries', - type: api.ApplyPluginsType.add, - initialValue: [ - ] - }); - libraries.forEach((library) => { - memo.resolve.alias.set( - library.name, - getUserLibDir({ library: library.name }) || library.path - ); - }); - // 选择在 chainWebpack 中进行以上 alias 的初始化,是为了支持用户使用 modifyPaths API 对 paths 进行改写 memo.resolve.alias.set('@', paths.absSrcPath); memo.resolve.alias.set('@@', paths.absTmpPath); - Object.keys(api.config.alias).forEach((key) => { - memo.resolve.alias.set(key, api.config.alias[key]); - }); - return memo; }); }; diff --git a/packages/fes-preset-built-in/src/plugins/features/analyze.js b/packages/fes-preset-built-in/src/plugins/features/analyze.js index ea643eee..86346225 100644 --- a/packages/fes-preset-built-in/src/plugins/features/analyze.js +++ b/packages/fes-preset-built-in/src/plugins/features/analyze.js @@ -28,15 +28,15 @@ export default (api) => { defaultSizes: 'parsed' // stat // gzip } }, - enableBy: () => !!(process.env.ANALYZE || process.env.ANALYZE_SSR) + enableBy: () => !!process.env.ANALYZE }); api.chainWebpack((webpackConfig, opts) => { const { type } = opts; - if (type === 'csr' && !process.env.ANALYZE_SSR) { + if (type === 'csr') { webpackConfig .plugin('bundle-analyzer') .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [ - api.config?.analyze || {} + api.config?.analyze || {} ]); } return webpackConfig; diff --git a/packages/fes-preset-built-in/src/plugins/features/chainWebpack.js b/packages/fes-preset-built-in/src/plugins/features/chainWebpack.js index fe3b1bce..88495f0c 100644 --- a/packages/fes-preset-built-in/src/plugins/features/chainWebpack.js +++ b/packages/fes-preset-built-in/src/plugins/features/chainWebpack.js @@ -1,7 +1,3 @@ -import { - winPath -} from '@umijs/utils'; - export default (api) => { api.describe({ key: 'chainWebpack', @@ -11,39 +7,4 @@ export default (api) => { } } }); - - api.chainWebpack((webpackConfig) => { - const cwd = api.cwd; - // 添加 .vue 后缀 - webpackConfig.resolve.extensions.merge([ - '.vue' - ]); - webpackConfig.module - .rule('js-in-node_modules').use('babel-loader').tap((options) => { - options.cacheDirectory = winPath(`${cwd}/.cache/babel-loader`); - return options; - }); - if (api.env !== 'development') { - webpackConfig - .optimization.splitChunks({ - cacheGroups: { - vendors: { - name: 'chunk-vendors', - test: /[\\/]node_modules[\\/]/, - priority: -10, - chunks: 'initial' - }, - common: { - name: 'chunk-common', - minChunks: 2, - priority: -20, - chunks: 'initial', - reuseExistingChunk: true - } - } - }); - } - - return webpackConfig; - }); }; diff --git a/packages/fes-preset-built-in/src/plugins/features/chunks.js b/packages/fes-preset-built-in/src/plugins/features/chunks.js deleted file mode 100644 index 5501f30c..00000000 --- a/packages/fes-preset-built-in/src/plugins/features/chunks.js +++ /dev/null @@ -1,11 +0,0 @@ - -export default (api) => { - api.describe({ - key: 'chunks', - config: { - schema(joi) { - return joi.array().items(joi.string()); - } - } - }); -}; diff --git a/packages/fes-preset-built-in/src/plugins/features/copy.js b/packages/fes-preset-built-in/src/plugins/features/copy.js index 846b59c1..252914ef 100644 --- a/packages/fes-preset-built-in/src/plugins/features/copy.js +++ b/packages/fes-preset-built-in/src/plugins/features/copy.js @@ -10,8 +10,8 @@ export default (api) => { from: joi.string(), to: joi.string() }), - joi.string(), - ), + joi.string() + ) ); } } diff --git a/packages/fes-preset-built-in/src/plugins/features/cssLoader.js b/packages/fes-preset-built-in/src/plugins/features/cssLoader.js index 6307bda8..d2019f49 100644 --- a/packages/fes-preset-built-in/src/plugins/features/cssLoader.js +++ b/packages/fes-preset-built-in/src/plugins/features/cssLoader.js @@ -3,6 +3,7 @@ export default (api) => { api.describe({ key: 'cssLoader', config: { + default: {}, schema(joi) { return joi .object({ @@ -11,7 +12,7 @@ export default (api) => { modules: joi.alternatives( joi.boolean(), joi.string(), - joi.object(), + joi.object() ), sourceMap: joi.boolean(), importLoaders: joi.number(), @@ -24,11 +25,11 @@ export default (api) => { 'camelCase', 'camelCaseOnly', 'dashes', - 'dashesOnly', + 'dashesOnly' ) }) .description( - 'more css-loader options see https://webpack.js.org/loaders/css-loader/#options', + 'more css-loader options see https://webpack.js.org/loaders/css-loader/#options' ); } } diff --git a/packages/fes-preset-built-in/src/plugins/features/cssnano.js b/packages/fes-preset-built-in/src/plugins/features/cssnano.js deleted file mode 100644 index 38213163..00000000 --- a/packages/fes-preset-built-in/src/plugins/features/cssnano.js +++ /dev/null @@ -1,16 +0,0 @@ - -export default (api) => { - api.describe({ - // https://cssnano.co/optimisations/ - key: 'cssnano', - config: { - default: { - mergeRules: false, - minifyFontValues: { removeQuotes: false } - }, - schema(joi) { - return joi.object(); - } - } - }); -}; diff --git a/packages/fes-preset-built-in/src/plugins/features/define.js b/packages/fes-preset-built-in/src/plugins/features/define.js index e8b2ea01..ca340a48 100644 --- a/packages/fes-preset-built-in/src/plugins/features/define.js +++ b/packages/fes-preset-built-in/src/plugins/features/define.js @@ -7,8 +7,6 @@ export default (api) => { return joi.object(); }, default: { - __VUE_OPTIONS_API__: true, - __VUE_PROD_DEVTOOLS__: false } } }); diff --git a/packages/fes-preset-built-in/src/plugins/features/devScripts.js b/packages/fes-preset-built-in/src/plugins/features/devScripts.js index 7260ab4e..8e5ccc6b 100644 --- a/packages/fes-preset-built-in/src/plugins/features/devScripts.js +++ b/packages/fes-preset-built-in/src/plugins/features/devScripts.js @@ -1,6 +1,3 @@ -import { - readFileSync -} from 'fs'; export default (api) => { api.describe({ @@ -14,100 +11,4 @@ export default (api) => { return api.env === 'development'; } }); - - api.addBeforeMiddlewares(() => (req, res, next) => { - if (req.path.includes('@@/devScripts.js')) { - api.applyPlugins({ - key: 'addDevScripts', - type: api.ApplyPluginsType.add, - initialValue: process.env.HMR !== 'none' - ? [ - readFileSync( - require.resolve( - '@umijs/bundler-webpack/bundled/webpackHotDevClient' - ), - 'utf-8' - ) - ] - : [] - }).then((scripts) => { - res.end( - scripts - .join('\r\n\r\n') - .replace( - /{}.SOCKET_SERVER/g, - JSON.stringify(process.env.SOCKET_SERVER || '') - ) - ); - }); - } else { - next(); - } - }); - - api.addHTMLHeadScripts(() => [{ - src: '@@/devScripts.js' - }]); - - api.onGenerateFiles(() => { - api.writeTmpFile({ - path: './core/devScripts.js', - content: process.env.HMR !== 'none' - ? ` -if (window.g_initWebpackHotDevClient) { - function tryApplyUpdates(onHotUpdateSuccess) { - // @ts-ignore - if (!module.hot) { - window.location.reload(); - return; - } - - function isUpdateAvailable() { - // @ts-ignore - return window.g_getMostRecentCompilationHash() !== __webpack_hash__; - } - - // TODO: is update available? - // @ts-ignore - if (!isUpdateAvailable() || module.hot.status() !== 'idle') { - return; - } - - function handleApplyUpdates(err, updatedModules) { - if (err || !updatedModules || window.g_getHadRuntimeError()) { - window.location.reload(); - return; - } - - onHotUpdateSuccess && onHotUpdateSuccess(); - - if (isUpdateAvailable()) { - // While we were updating, there was a new update! Do it again. - tryApplyUpdates(); - } - } - - // @ts-ignore - module.hot.check(true).then( - function (updatedModules) { - handleApplyUpdates(null, updatedModules); - }, - function (err) { - handleApplyUpdates(err, null); - }, - ); - } - - window.g_initWebpackHotDevClient({ - tryApplyUpdates, - }); -} - ` - : '' - }); - }); - - api.addEntryImportsAhead(() => [{ - source: '@@/core/devScripts' - }]); }; diff --git a/packages/fes-preset-built-in/src/plugins/features/extraBabelPlugins.js b/packages/fes-preset-built-in/src/plugins/features/extraBabelPlugins.js index 5b9f627a..0719d858 100644 --- a/packages/fes-preset-built-in/src/plugins/features/extraBabelPlugins.js +++ b/packages/fes-preset-built-in/src/plugins/features/extraBabelPlugins.js @@ -1,4 +1,3 @@ -import { winPath } from '@umijs/utils'; export default (api) => { api.describe({ @@ -9,13 +8,4 @@ export default (api) => { } } }); - - api.modifyBabelOpts((babelOpts) => { - babelOpts.cacheDirectory = process.env.BABEL_CACHE !== 'none' - ? winPath(`${api.cwd}/.cache/babel-loader`) - : false; - babelOpts.plugins.push(require.resolve('@vue/babel-plugin-jsx')); - - return babelOpts; - }); }; diff --git a/packages/fes-preset-built-in/src/plugins/features/extraBabelPresets.js b/packages/fes-preset-built-in/src/plugins/features/extraBabelPresets.js index b8257605..7b620e09 100644 --- a/packages/fes-preset-built-in/src/plugins/features/extraBabelPresets.js +++ b/packages/fes-preset-built-in/src/plugins/features/extraBabelPresets.js @@ -8,16 +8,4 @@ export default (api) => { } } }); - api.modifyBabelPresetOpts(opts => Object.assign({}, opts, { - typescript: false, - env: { - useBuiltIns: 'entry', - corejs: 3, - modules: false - }, - react: false, - reactRemovePropTypes: false, - reactRequire: false, - svgr: false - })); }; diff --git a/packages/fes-preset-built-in/src/plugins/features/hardSource.js b/packages/fes-preset-built-in/src/plugins/features/hardSource.js index 7622f399..7a777510 100644 --- a/packages/fes-preset-built-in/src/plugins/features/hardSource.js +++ b/packages/fes-preset-built-in/src/plugins/features/hardSource.js @@ -1,7 +1,7 @@ -import { - winPath -} from '@umijs/utils'; -import HardSourceWebpackPlugin from 'hard-source-webpack-plugin'; +// import { +// winPath +// } from '@umijs/utils'; +// import HardSourceWebpackPlugin from 'hard-source-webpack-plugin'; export default (api) => { api.describe({ @@ -13,31 +13,31 @@ export default (api) => { } }); - api.chainWebpack((webpackConfig) => { - const cwd = api.cwd; - if (api.env === 'development') { - webpackConfig - .plugin('hardSource') - .use(HardSourceWebpackPlugin, [{ - cacheDirectory: winPath(`${cwd}/.cache/hard-source/[confighash]`), - ...api.config.hardSource || {} - }]); - webpackConfig - .plugin('hardSourceExclude') - .use(HardSourceWebpackPlugin.ExcludeModulePlugin, [ - [ - { - // HardSource works with mini-css-extract-plugin but due to how - // mini-css emits assets, assets are not emitted on repeated builds with - // mini-css and hard-source together. Ignoring the mini-css loader - // modules, but not the other css loader modules, excludes the modules - // that mini-css needs rebuilt to output assets every time. - test: /mini-css-extract-plugin[\\/]dist[\\/]loader/ - } - ] - ]); - } + // api.chainWebpack((webpackConfig) => { + // const cwd = api.cwd; + // if (api.env === 'development') { + // webpackConfig + // .plugin('hardSource') + // .use(HardSourceWebpackPlugin, [{ + // cacheDirectory: winPath(`${cwd}/.cache/hard-source/[confighash]`), + // ...api.config.hardSource || {} + // }]); + // webpackConfig + // .plugin('hardSourceExclude') + // .use(HardSourceWebpackPlugin.ExcludeModulePlugin, [ + // [ + // { + // // HardSource works with mini-css-extract-plugin but due to how + // // mini-css emits assets, assets are not emitted on repeated builds with + // // mini-css and hard-source together. Ignoring the mini-css loader + // // modules, but not the other css loader modules, excludes the modules + // // that mini-css needs rebuilt to output assets every time. + // test: /mini-css-extract-plugin[\\/]dist[\\/]loader/ + // } + // ] + // ]); + // } - return webpackConfig; - }); + // return webpackConfig; + // }); }; diff --git a/packages/fes-preset-built-in/src/plugins/features/hash.js b/packages/fes-preset-built-in/src/plugins/features/hash.js deleted file mode 100644 index 24f57403..00000000 --- a/packages/fes-preset-built-in/src/plugins/features/hash.js +++ /dev/null @@ -1,12 +0,0 @@ - -export default (api) => { - api.describe({ - key: 'hash', - config: { - default: true, - schema(joi) { - return joi.boolean(); - } - } - }); -}; diff --git a/packages/fes-preset-built-in/src/plugins/features/html.js b/packages/fes-preset-built-in/src/plugins/features/html.js index 3a5d4924..d3ee4d73 100644 --- a/packages/fes-preset-built-in/src/plugins/features/html.js +++ b/packages/fes-preset-built-in/src/plugins/features/html.js @@ -1,6 +1,3 @@ -import { resolve, join } from 'path'; -import { existsSync } from 'fs'; - export default (api) => { api.describe({ key: 'html', @@ -20,103 +17,4 @@ export default (api) => { } } }); - - api.chainWebpack(async (webpackConfig) => { - const isProd = api.env === 'production'; - const htmlOptions = { - templateParameters: (compilation, assets, pluginOptions) => { - // enhance html-webpack-plugin's built in template params - let stats; - return { - // make stats lazy as it is expensive - get webpack() { - // eslint-disable-next-line - return stats || (stats = compilation.getStats().toJson()); - }, - compilation, - webpackConfig: compilation.options, - htmlWebpackPlugin: { - files: assets, - options: pluginOptions - } - }; - }, - ...api.config.html.options - }; - - - if (isProd) { - Object.assign(htmlOptions, { - minify: { - removeComments: true, - collapseWhitespace: true, - collapseBooleanAttributes: true, - removeScriptTypeAttributes: true - // more options: - // https://github.com/kangax/html-minifier#options-quick-reference - } - }); - } - - const HTMLPlugin = require('html-webpack-plugin'); - const HtmlWebpackTagsPlugin = require('html-webpack-tags-plugin'); - const PreloadPlugin = require('@vue/preload-webpack-plugin'); - const multiPageConfig = api.config.html.pages; - const htmlPath = join(api.paths.cwd, 'public/index.html'); - const defaultHtmlPath = resolve(__dirname, 'index-default.html'); - const publicCopyIgnore = ['.DS_Store']; - - if (!multiPageConfig) { - // default, single page setup. - htmlOptions.template = existsSync(htmlPath) - ? htmlPath - : defaultHtmlPath; - - publicCopyIgnore.push({ - glob: htmlOptions.template, - matchBase: false - }); - - webpackConfig - .plugin('html') - .use(HTMLPlugin, [htmlOptions]); - - // TODO onlyHtml 将资源注入 html 中的逻辑 - if (!htmlOptions.onlyHtml || htmlOptions.preload !== false) { - // inject preload/prefetch to HTML - webpackConfig - .plugin('preload') - .use(PreloadPlugin, [{ - rel: 'preload', - include: 'initial', - fileBlacklist: [/\.map$/, /hot-update\.js$/] - }]); - - webpackConfig - .plugin('prefetch') - .use(PreloadPlugin, [{ - rel: 'prefetch', - include: 'asyncChunks' - }]); - } - } else { - // TODO 支持多页 - } - - if (!isProd) { - const headScripts = await api.applyPlugins({ - key: 'addHTMLHeadScripts', - type: api.ApplyPluginsType.add, - initialState: [] - }); - webpackConfig - .plugin('html-tags') - .use(HtmlWebpackTagsPlugin, [{ - append: false, - scripts: headScripts.map(script => ({ - path: script.src - })) - }]); - } - }); }; diff --git a/packages/fes-preset-built-in/src/plugins/features/imageMinimizer.js b/packages/fes-preset-built-in/src/plugins/features/imageMinimizer.js deleted file mode 100644 index 4aaae365..00000000 --- a/packages/fes-preset-built-in/src/plugins/features/imageMinimizer.js +++ /dev/null @@ -1,23 +0,0 @@ -// import ImageMinimizerPlugin from 'image-minimizer-webpack-plugin'; - -export default (api) => { - api.describe({ - key: 'imageMinimizer', - config: { - schema(joi) { - return joi.object(); - }, - default: { - disable: true - } - } - }); - - api.chainWebpack((webpackConfig) => { - if (!api.config.imageMinimizer.disable && api.env === 'production') { - // TODO 图片压缩 - } - - return webpackConfig; - }); -}; diff --git a/packages/fes-preset-built-in/src/plugins/features/nodeModulesTransform.js b/packages/fes-preset-built-in/src/plugins/features/nodeModulesTransform.js index c350b20b..157272e8 100644 --- a/packages/fes-preset-built-in/src/plugins/features/nodeModulesTransform.js +++ b/packages/fes-preset-built-in/src/plugins/features/nodeModulesTransform.js @@ -4,12 +4,10 @@ export default (api) => { key: 'nodeModulesTransform', config: { default: { - type: 'all', exclude: [] }, schema(joi) { return joi.object({ - type: joi.string().valid('all', 'none'), exclude: joi.array().items(joi.string()) }); } diff --git a/packages/fes-preset-built-in/src/plugins/features/styleLoader.js b/packages/fes-preset-built-in/src/plugins/features/styleLoader.js deleted file mode 100644 index 6ec2a014..00000000 --- a/packages/fes-preset-built-in/src/plugins/features/styleLoader.js +++ /dev/null @@ -1,10 +0,0 @@ -export default (api) => { - api.describe({ - key: 'styleLoader', - config: { - schema(joi) { - return joi.object(); - } - } - }); -}; diff --git a/packages/fes-preset-built-in/src/plugins/features/targets.js b/packages/fes-preset-built-in/src/plugins/features/targets.js index fc839b1a..f3fb0ee1 100644 --- a/packages/fes-preset-built-in/src/plugins/features/targets.js +++ b/packages/fes-preset-built-in/src/plugins/features/targets.js @@ -4,7 +4,6 @@ export default (api) => { key: 'targets', config: { default: { - node: true, chrome: 49, firefox: 64, safari: 10, diff --git a/packages/fes-preset-built-in/src/plugins/features/vueLoader.js b/packages/fes-preset-built-in/src/plugins/features/vueLoader.js index c277942d..c2c2f02a 100644 --- a/packages/fes-preset-built-in/src/plugins/features/vueLoader.js +++ b/packages/fes-preset-built-in/src/plugins/features/vueLoader.js @@ -8,28 +8,9 @@ export default (api) => { return joi .object({}) .description( - 'more vue-loader options see https://vue-loader.vuejs.org/', + 'more vue-loader options see https://vue-loader.vuejs.org/' ); } } }); - api.chainWebpack((webpackConfig) => { - // 添加 .vue 后缀 - webpackConfig.module - .rule('vue') - .test(/\.vue$/) - .use('vue-loader') - .loader(require.resolve('vue-loader')) - .options({ - babelParserPlugins: ['jsx', 'classProperties', 'decorators-legacy'] - }) - .end() - .end(); - - webpackConfig - .plugin('vue-loader') - .use(require('vue-loader').VueLoaderPlugin); - - return webpackConfig; - }); }; diff --git a/packages/fes-preset-built-in/src/plugins/registerMethods.js b/packages/fes-preset-built-in/src/plugins/registerMethods.js index 1b6b11e1..5b5749c5 100644 --- a/packages/fes-preset-built-in/src/plugins/registerMethods.js +++ b/packages/fes-preset-built-in/src/plugins/registerMethods.js @@ -25,7 +25,6 @@ export default function (api) { 'modifyBundleImplementor', 'modifyBundleConfigOpts', 'modifyBundleConfig', - 'modifyBundleConfigs', 'modifyBabelOpts', 'modifyBabelPresetOpts', 'chainWebpack', diff --git a/packages/fes-preset-built-in/src/utils/constants.js b/packages/fes-preset-built-in/src/utils/constants.js index c93391a4..791f82a5 100644 --- a/packages/fes-preset-built-in/src/utils/constants.js +++ b/packages/fes-preset-built-in/src/utils/constants.js @@ -2,5 +2,5 @@ import { winPath } from '@umijs/utils'; import { dirname } from 'path'; export const runtimePath = winPath( - dirname(require.resolve('@webank/fes-runtime/package.json')), + dirname(require.resolve('@webank/fes-runtime/package.json')) ); diff --git a/packages/fes-template-h5/.fes.js b/packages/fes-template-h5/.fes.js index ff0906c4..eb14e8c3 100644 --- a/packages/fes-template-h5/.fes.js +++ b/packages/fes-template-h5/.fes.js @@ -15,9 +15,6 @@ export default { title: '海贼王' } }, - imageMinimizer: { - disable: false - }, extraPostCSSPlugins: [ pxtoviewport({ unitToConvert: 'px', diff --git a/packages/fes-template-h5/src/pages/index.vue b/packages/fes-template-h5/src/pages/index.vue index 4168d0b4..ec0067d8 100644 --- a/packages/fes-template-h5/src/pages/index.vue +++ b/packages/fes-template-h5/src/pages/index.vue @@ -1,7 +1,7 @@