From b027abe5e0493fe434dbec9011c012f48b438f23 Mon Sep 17 00:00:00 2001 From: "friday.fj" Date: Tue, 29 Mar 2022 15:27:27 +0800 Subject: [PATCH 1/4] feat(bundler-webpack): add https params in config --- examples/boilerplate/.umirc.ts | 1 + packages/bundler-webpack/src/schema.test.ts | 1 + packages/bundler-webpack/src/schema.ts | 1 + packages/bundler-webpack/src/types.ts | 7 +++++++ 4 files changed, 10 insertions(+) diff --git a/examples/boilerplate/.umirc.ts b/examples/boilerplate/.umirc.ts index 8429a52de..be54b4a87 100644 --- a/examples/boilerplate/.umirc.ts +++ b/examples/boilerplate/.umirc.ts @@ -23,6 +23,7 @@ export default { }, // vite: {}, deadCode: {}, + https: {}, // fastRefresh: false, // favicon: 'https://sivers.com/favicon.ico', headScripts: [`console.log('head script')`], diff --git a/packages/bundler-webpack/src/schema.test.ts b/packages/bundler-webpack/src/schema.test.ts index b9ffbf55e..42b29652b 100644 --- a/packages/bundler-webpack/src/schema.test.ts +++ b/packages/bundler-webpack/src/schema.test.ts @@ -20,6 +20,7 @@ const config = { cssMinifierOptions: {}, define: {}, deadCode: {}, + https: {}, depTranspiler: 'esbuild', devtool: 'cheap-module-source-map', externals: { diff --git a/packages/bundler-webpack/src/schema.ts b/packages/bundler-webpack/src/schema.ts index 9fd3e29c7..a4e96e6f8 100644 --- a/packages/bundler-webpack/src/schema.ts +++ b/packages/bundler-webpack/src/schema.ts @@ -72,6 +72,7 @@ export function getSchemas(): Record any> { fastRefresh: (Joi) => Joi.boolean(), forkTSChecker: (Joi) => Joi.object(), hash: (Joi) => Joi.boolean(), + https: (Joi) => Joi.object(), ignoreMomentLocale: (Joi) => Joi.boolean(), inlineLimit: (Joi) => Joi.number(), jsMinifier: (Joi) => diff --git a/packages/bundler-webpack/src/types.ts b/packages/bundler-webpack/src/types.ts index ebc625597..9f77ab0b9 100644 --- a/packages/bundler-webpack/src/types.ts +++ b/packages/bundler-webpack/src/types.ts @@ -47,6 +47,12 @@ export interface DeadCodeParams { context?: string; } +export interface HttpsParams { + key?: string; + cert?: string; + hosts?: string[]; // 默认值 ['localhost', '127.0.0.1'] +} + export interface IConfig { alias?: Record; autoCSSModules?: boolean; @@ -61,6 +67,7 @@ export interface IConfig { depTranspiler?: Transpiler; devtool?: Config.DevTool; deadCode?: DeadCodeParams; + https?: HttpsParams; externals?: WebpackConfig['externals']; esm?: { [key: string]: any }; extraBabelPlugins?: IBabelPlugin[]; From 32335bf6e8299aecd0ef6ef826a64dd35dcf4055 Mon Sep 17 00:00:00 2001 From: "friday.fj" Date: Wed, 30 Mar 2022 18:17:50 +0800 Subject: [PATCH 2/4] feat(bundler-webpack): add https for server --- .../bundler-webpack/client/client/client.js | 3 +- packages/bundler-webpack/src/client/client.ts | 3 +- packages/bundler-webpack/src/server/server.ts | 14 ++- packages/bundler-webpack/src/server/ws.ts | 5 +- packages/bundler-webpack/src/utils/server.ts | 106 ++++++++++++++++++ 5 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 packages/bundler-webpack/src/utils/server.ts diff --git a/packages/bundler-webpack/client/client/client.js b/packages/bundler-webpack/client/client/client.js index 02c6e16bd..705750e05 100644 --- a/packages/bundler-webpack/client/client/client.js +++ b/packages/bundler-webpack/client/client/client.js @@ -15,7 +15,8 @@ import { formatWebpackMessages } from '../utils/formatWebpackMessages'; console.log('[webpack] connecting...'); let pingTimer = null; const host = location.host; -const wsUrl = `ws://${host}`; +const isHttps = location.protocol === 'https:'; +const wsUrl = `${isHttps ? 'wss' : 'ws'}://${host}`; let isFirstCompilation = true; let mostRecentCompilationHash = null; let hasCompileErrors = false; diff --git a/packages/bundler-webpack/src/client/client.ts b/packages/bundler-webpack/src/client/client.ts index 84e4d169b..670d58f4a 100644 --- a/packages/bundler-webpack/src/client/client.ts +++ b/packages/bundler-webpack/src/client/client.ts @@ -8,7 +8,8 @@ console.log('[webpack] connecting...'); let pingTimer: NodeJS.Timer | null = null; const host = location.host; -const wsUrl = `ws://${host}`; +const isHttps = location.protocol === 'https:'; +const wsUrl = `${isHttps ? 'wss' : 'ws'}://${host}`; let isFirstCompilation = true; let mostRecentCompilationHash: string | null = null; let hasCompileErrors = false; diff --git a/packages/bundler-webpack/src/server/server.ts b/packages/bundler-webpack/src/server/server.ts index 0b2f8db49..19e3dc02d 100644 --- a/packages/bundler-webpack/src/server/server.ts +++ b/packages/bundler-webpack/src/server/server.ts @@ -5,10 +5,10 @@ import webpack, { } from '@umijs/bundler-webpack/compiled/webpack'; import { chalk, logger } from '@umijs/utils'; import { createReadStream, existsSync } from 'fs'; -import http from 'http'; import { join } from 'path'; import { MESSAGE_TYPE } from '../constants'; import { IConfig } from '../types'; +import { getServer } from '../utils/server'; import { createWebSocketServer } from './ws'; interface IOpts { @@ -205,7 +205,11 @@ export async function createServer(opts: IOpts) { } }); - const server = http.createServer(app); + const server = await getServer(app, userConfig.https); + if (!server) { + return null; + } + const ws = createWebSocketServer(server); ws.wss.on('connection', (socket) => { @@ -214,10 +218,14 @@ export async function createServer(opts: IOpts) { } }); + const protocol = userConfig.https ? 'https:' : 'http:'; const port = opts.port || 8000; + server.listen(port, () => { const host = opts.host && opts.host !== '0.0.0.0' ? opts.host : '127.0.0.1'; - logger.ready(`App listening at ${chalk.green(`http://${host}:${port}`)}`); + logger.ready( + `App listening at ${chalk.green(`${protocol}//${host}:${port}`)}`, + ); }); return server; diff --git a/packages/bundler-webpack/src/server/ws.ts b/packages/bundler-webpack/src/server/ws.ts index 53b552345..991d7e2af 100644 --- a/packages/bundler-webpack/src/server/ws.ts +++ b/packages/bundler-webpack/src/server/ws.ts @@ -1,8 +1,9 @@ import { chalk } from '@umijs/utils'; -import { Server } from 'http'; +import { Server as HttpServer } from 'http'; +import { Server as HttpsServer } from 'https'; import WebSocket from '../../compiled/ws'; -export function createWebSocketServer(server: Server) { +export function createWebSocketServer(server: HttpServer | HttpsServer) { const wss = new WebSocket.Server({ noServer: true, }); diff --git a/packages/bundler-webpack/src/utils/server.ts b/packages/bundler-webpack/src/utils/server.ts new file mode 100644 index 000000000..3d95ba291 --- /dev/null +++ b/packages/bundler-webpack/src/utils/server.ts @@ -0,0 +1,106 @@ +import { chalk, logger } from '@umijs/utils'; +import { exec } from 'child_process'; +import { readFileSync } from 'fs'; +import http, { RequestListener } from 'http'; +import https from 'https'; +import { join } from 'path'; +import { HttpsParams } from '../types'; + +const defaultHttpsHosts: HttpsParams['hosts'] = ['localhost', '127.0.0.1']; + +/** + * Check if mkcert is installed + */ +const mkcertCmdChecker = (): Promise => { + return new Promise((resolve, reject) => { + exec('mkcert -help', (error, stdout) => { + if (!error && stdout?.includes?.('mkcert')) { + resolve(true); + } else { + reject(false); + } + }); + }); +}; + +/** + * Generate key and certificate files in https mode. + */ +const generateCertFiles = async ( + hosts = defaultHttpsHosts, +): Promise> => { + return new Promise((resolve, reject) => { + logger.warn('[https] No key or cert has been passed in.'); + + mkcertCmdChecker() + .then(() => { + logger.wait('[https] Generating cert and key files...'); + + const certFilePath = join(__dirname, 'umi.pem'); + const keyFilePath = join(__dirname, 'umi.key.pem'); + + exec( + `mkcert -cert-file ${certFilePath} -key-file ${keyFilePath} ${hosts.join( + ' ', + )}`, + (error) => { + if (error) { + reject({}); + } else { + resolve({ + key: keyFilePath, + cert: certFilePath, + }); + } + }, + ); + }) + .catch(() => { + reject(new Error('[https] The mkcert has not been installed.')); + logger.info( + [ + '[https] Please follow the guide to install manually.\n', + `\tMac: ${chalk.green( + [ + 'brew install mkcert', + 'brew install nss', + 'mkcert -install', + ].join(' + '), + )}\n`, + `\tWindows: ${chalk.green( + 'https://github.com/FiloSottile/mkcert#windows', + )}\n`, + `\tLinux: ${chalk.green( + 'https://github.com/FiloSottile/mkcert#linux', + )}\n`, + ].join(''), + ); + }); + }); +}; + +export const getServer = async ( + app: RequestListener, + httpsConfig?: HttpsParams, +) => { + if (!httpsConfig) { + return http.createServer(app); + } + + logger.wait('[https] Starting service in https mode...'); + + const isHttpsConfigLegally = httpsConfig.cert && httpsConfig.key; + const { key, cert } = isHttpsConfigLegally + ? httpsConfig + : await generateCertFiles(httpsConfig.hosts); + + if (key && cert) { + return https.createServer( + { + key: readFileSync(key, 'utf8'), + cert: readFileSync(cert, 'utf8'), + }, + app, + ); + } +}; From 89556630c36ddd4b086899d0fb23ac1f748a0c7f Mon Sep 17 00:00:00 2001 From: "friday.fj" Date: Mon, 25 Apr 2022 11:43:11 +0800 Subject: [PATCH 3/4] feat(bundler-webpack): https to http2 --- packages/bundler-webpack/package.json | 4 +++- packages/bundler-webpack/src/server/https.ts | 6 ++++-- packages/bundler-webpack/src/server/ws.ts | 6 +++++- pnpm-lock.yaml | 20 ++++++++++++-------- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/packages/bundler-webpack/package.json b/packages/bundler-webpack/package.json index 5e91b98d4..c7447f90f 100644 --- a/packages/bundler-webpack/package.json +++ b/packages/bundler-webpack/package.json @@ -45,10 +45,12 @@ "node-libs-browser": "2.2.1", "postcss": "^8.4.12", "postcss-preset-env": "7.4.3", - "react-error-overlay": "6.0.9" + "react-error-overlay": "6.0.9", + "spdy": "^4.0.2" }, "devDependencies": { "@swc/core": "1.2.165", + "@types/spdy": "^3.4.5", "@types/webpack-sources": "3.2.0", "@types/ws": "8.5.3", "autoprefixer": "10.4.4", diff --git a/packages/bundler-webpack/src/server/https.ts b/packages/bundler-webpack/src/server/https.ts index 0f159f569..75817aa4a 100644 --- a/packages/bundler-webpack/src/server/https.ts +++ b/packages/bundler-webpack/src/server/https.ts @@ -1,8 +1,8 @@ import { chalk, execa, logger } from '@umijs/utils'; import { existsSync, readFileSync } from 'fs'; import { RequestListener } from 'http'; -import https from 'https'; import { join } from 'path'; +import spdy from 'spdy'; import { HttpsParams } from '../types'; const defaultHttpsHosts: HttpsParams['hosts'] = ['localhost', '127.0.0.1']; @@ -62,11 +62,13 @@ export async function createHttpsServer( } // Create server - return https.createServer( + const http2Service = spdy.createServer( { key: readFileSync(key, 'utf-8'), cert: readFileSync(cert, 'utf-8'), }, app, ); + + return http2Service; } diff --git a/packages/bundler-webpack/src/server/ws.ts b/packages/bundler-webpack/src/server/ws.ts index 991d7e2af..f08756e98 100644 --- a/packages/bundler-webpack/src/server/ws.ts +++ b/packages/bundler-webpack/src/server/ws.ts @@ -1,9 +1,13 @@ import { chalk } from '@umijs/utils'; import { Server as HttpServer } from 'http'; +import { Http2Server } from 'http2'; import { Server as HttpsServer } from 'https'; +import { Server } from 'spdy'; import WebSocket from '../../compiled/ws'; -export function createWebSocketServer(server: HttpServer | HttpsServer) { +export function createWebSocketServer( + server: HttpServer | HttpsServer | Http2Server | Server, +) { const wss = new WebSocket.Server({ noServer: true, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0468c729a..0a60508c4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -158,8 +158,10 @@ importers: examples/boilerplate: specifiers: + spdy: ^4.0.2 umi: 4.0.0-canary.20220424.1 dependencies: + spdy: 4.0.2 umi: link:../../packages/umi examples/bug-mfsu-fast-refresh: @@ -670,6 +672,7 @@ importers: '@svgr/plugin-svgo': ^6.2.0 '@swc/core': 1.2.165 '@types/hapi__joi': 17.1.8 + '@types/spdy': ^3.4.5 '@types/webpack-sources': 3.2.0 '@types/ws': 8.5.3 '@umijs/babel-preset-umi': 4.0.0-canary.20220424.1 @@ -700,6 +703,7 @@ importers: react-refresh: 0.12.0 sass-loader: 12.6.0 schema-utils: 4.0.0 + spdy: ^4.0.2 speed-measure-webpack-plugin: 1.5.0 style-loader: 3.3.1 svgo-loader: 3.0.0 @@ -731,8 +735,10 @@ importers: postcss: 8.4.12 postcss-preset-env: 7.4.3_postcss@8.4.12 react-error-overlay: 6.0.9 + spdy: 4.0.2 devDependencies: '@swc/core': 1.2.165 + '@types/spdy': 3.4.5 '@types/webpack-sources': 3.2.0 '@types/ws': 8.5.3 autoprefixer: 10.4.4_postcss@8.4.12 @@ -7801,6 +7807,12 @@ packages: resolution: {integrity: sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==} dev: true + /@types/spdy/3.4.5: + resolution: {integrity: sha512-/33fIRK/aqkKNxg9BSjpzt1ucmvPremgeDywm9z2C2mOlIh5Ljjvgc3UhQHqwXsSLDLHPT9jlsnrjKQ1XiVJzA==} + dependencies: + '@types/node': 17.0.25 + dev: true + /@types/stack-utils/2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: true @@ -14142,7 +14154,6 @@ packages: /handle-thing/2.0.1: resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} - dev: true /handlebars/4.7.7: resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==} @@ -14363,7 +14374,6 @@ packages: obuf: 1.1.2 readable-stream: 2.3.7 wbuf: 1.7.3 - dev: true /html-encoding-sniffer/2.0.1: resolution: {integrity: sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==} @@ -14433,7 +14443,6 @@ packages: /http-deceiver/1.2.7: resolution: {integrity: sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=} - dev: true /http-errors/1.6.3: resolution: {integrity: sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=} @@ -18367,7 +18376,6 @@ packages: /obuf/1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} - dev: true /omit.js/2.0.2: resolution: {integrity: sha512-hJmu9D+bNB40YpL9jYebQl4lsTW6yEHRTroJzNLqQJYHm7c+NQnJGfZmIWh8S3q3KoaxV1aLhV6B3+0N0/kyJg==} @@ -22646,7 +22654,6 @@ packages: /select-hose/2.0.0: resolution: {integrity: sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=} - dev: true /selfsigned/2.0.1: resolution: {integrity: sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==} @@ -23144,7 +23151,6 @@ packages: wbuf: 1.7.3 transitivePeerDependencies: - supports-color - dev: true /spdy/4.0.2: resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==} @@ -23157,7 +23163,6 @@ packages: spdy-transport: 3.0.0 transitivePeerDependencies: - supports-color - dev: true /specificity/0.4.1: resolution: {integrity: sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==} @@ -25187,7 +25192,6 @@ packages: resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} dependencies: minimalistic-assert: 1.0.1 - dev: true /wcwidth/1.0.1: resolution: {integrity: sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=} From 95048005909a84e5640b2a84907f645ee971c592 Mon Sep 17 00:00:00 2001 From: "friday.fj" Date: Mon, 25 Apr 2022 13:46:15 +0800 Subject: [PATCH 4/4] feat: update pnpm lock file --- pnpm-lock.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0a60508c4..435efadcb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -158,10 +158,8 @@ importers: examples/boilerplate: specifiers: - spdy: ^4.0.2 umi: 4.0.0-canary.20220424.1 dependencies: - spdy: 4.0.2 umi: link:../../packages/umi examples/bug-mfsu-fast-refresh: