Skip to content

serve 时监测配置文件变更 #133

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,3 @@
收益有限,可能影响 builder 的安装,低优先级处理

### sourcemap

### watch build config change

不是痛点,低优先级处理

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果只改 dev proxy 配置的时候
可以只重启 dev server
就完美了

47 changes: 43 additions & 4 deletions src/serve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,56 @@
* @author nighca <[email protected]>
*/

import fs from 'fs'
import url from 'url'
import webpack from 'webpack'
import WebpackDevServer from 'webpack-dev-server'
import { Config as ProxyConfig } from 'http-proxy-middleware'
import logger from './utils/logger'
import { getPageFilename, getPathFromUrl, logLifecycle } from './utils'
import { getPageFilename, getPathFromUrl, logLifecycle, watchFile } from './utils'
import { getServeConfig } from './webpack'
import { BuildConfig, DevProxy, findBuildConfig } from './utils/build-conf'
import { BuildConfig, DevProxy, findBuildConfig, watchBuildConfig } from './utils/build-conf'
import { entries, mapValues } from 'lodash'
import { abs } from './utils/paths'

// 业务项目的配置文件,变更时需要重启 server
const projectConfigFiles = [
'tsconfig.json'
]

async function serve(port: number) {
let stopDevServer = await runDevServer(port)

async function restartDevServer() {
await stopDevServer?.()
stopDevServer = await runDevServer(port)
}

const disposers: Array<() => void> = []

disposers.push(watchBuildConfig(async () => {
logger.info('Detected build config change, restarting server...')
restartDevServer()
}))

projectConfigFiles.forEach(file => {
const filePath = abs(file)
if (fs.existsSync(filePath)) {
disposers.push(watchFile(filePath, async () => {
logger.info(`Detected ${file} change, restarting server...`)
restartDevServer()
}))
}
})

process.on('exit', () => {
disposers.forEach(disposer => disposer())
})
}

async function runDevServer(port: number) {
const buildConfig = await findBuildConfig()
const webpackConfig = await getServeConfig()

logger.debug('webpack config:', webpackConfig)

const devServerConfig: WebpackDevServer.Configuration = {
Expand All @@ -41,7 +77,10 @@ async function serve(port: number) {

const host = '0.0.0.0'
server.listen(port, host, () => {
logger.info(`Starting server on ${host}:${port}`)
logger.info(`Server started on ${host}:${port}`)
})
return () => new Promise<void>(resolve => {
server.close(resolve)
})
}

Expand Down
27 changes: 21 additions & 6 deletions src/utils/build-conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { mapValues } from 'lodash'
import fs from 'fs'
import path from 'path'
import files from '../constants/files'
import { extend } from '.'
import { extend, watchFile } from '.'
import { getBuildConfigFilePath, abs } from './paths'
import logger from './logger'
import { Transform } from '../constants/transform'
Expand Down Expand Up @@ -256,17 +256,22 @@ function normalizeConfig({
}
}

/** 获取最终使用的 build config 文件路径 */
function resolveBuildConfigFilePath() {
// 若指定了 build config file path,则使用之
// 否则使用 build root 下的 build config 文件
return getBuildConfigFilePath() || abs(files.config)
}

let cached: Promise<BuildConfig> | null = null

/** find config file and resolve config content based on paths info */
export async function findBuildConfig(): Promise<BuildConfig> {
if (cached) {
export async function findBuildConfig(disableCache = false): Promise<BuildConfig> {
if (cached && !disableCache) {
return cached
}

// 若指定了 build config file path,则使用之
// 否则使用 build root 下的 build config 文件
const configFilePath = getBuildConfigFilePath() || abs(files.config)
const configFilePath = resolveBuildConfigFilePath()
logger.debug(`use build config file: ${configFilePath}`)

return cached = readAndResolveConfig(configFilePath).then(
Expand All @@ -290,3 +295,13 @@ export function getNeedAnalyze() {
export function setNeedAnalyze(value: boolean) {
needAnalyze = value
}

/** watch build config, call listener when build config changes */
export function watchBuildConfig(listener: (config: BuildConfig) => void) {
const configFilePath = resolveBuildConfigFilePath()
logger.debug(`watch build config file: ${configFilePath}`)
return watchFile(configFilePath, async () => {
const buildConfig = await findBuildConfig(true) // 把 build config 缓存刷掉
listener(buildConfig)
})
}
44 changes: 25 additions & 19 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* @author nighca <[email protected]>
*/

import fs from 'fs'
import { debounce } from 'lodash'
import { Logger } from 'log4js'
import { parse as parseUrl } from 'url'

Expand Down Expand Up @@ -123,22 +125,26 @@ export function getPageFilename(pageName: string) {
return `${pageName}.html`
}

// TODO
// export function getDefaultExtensions(webpackConfig) {
// return webpackConfig.resolve.extensions.map(
// extension => extension.replace(/^\./, '')
// )
// }

// TODO
// function runWebpackCompiler(compiler) {
// return new Promise((resolve, reject) => {
// compiler.run((err, stats) => {
// if (err || stats.hasErrors()) {
// reject(err || stats.toJson().errors)
// return
// }
// resolve(stats)
// })
// })
// }
/** 监听文件内容变化,会对内容做比对,适用于体积较小的文本文件 */
export function watchFile(filePath: string, listener: (content: string) => void) {

function readFile() {
return fs.readFileSync(filePath, { encoding: 'utf-8' })
}

let previousCnt = readFile()

// 1. debounce 是因为有时候可能会在短时间内触发多次变更事件,这里做下合并
// 2. 比较文件内容是因为触发变更事件时文件的内容可能没有其实没有变化,这里假设使用方只关心内容的变化
const onChange = debounce(() => {
const currentCnt = readFile()
if (previousCnt !== currentCnt) {
previousCnt = currentCnt
listener(currentCnt)
}
}, 100)

const fsWatcher = fs.watch(filePath)
fsWatcher.on('change', onChange)
return () => fsWatcher.close()
}
4 changes: 2 additions & 2 deletions src/webpack/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ function addTransform(
}

const resourcePattern = {
include: makeExtensionPattern(resource.include),
include: makeExtensionPattern(extension),
exclude: excludePatterns
}

Expand All @@ -126,7 +126,7 @@ function addTransform(
}

const appendRule = (previousConfig: Configuration, ruleBase: Partial<RuleSetRule>) => produce(previousConfig, (nextConfig: Configuration) => {
const rule = makeRule(resource.include, resourcePattern, contextPattern, ruleBase)
const rule = makeRule(extension, resourcePattern, contextPattern, ruleBase)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这边 extensionresource.include 值是一样的,前者更合适一点

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nip: 上面 119 行的一起替换下? include: makeExtensionPattern(resource.include)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我看下

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done 47285c1

nextConfig.module!.rules!.push(rule)
})

Expand Down