Skip to content
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

Sunsetting webpack-serve #1195

Merged
merged 12 commits into from
Jan 27, 2019
101 changes: 53 additions & 48 deletions packages/@vuepress/core/lib/dev.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
'use strict'

module.exports = async function dev (sourceDir, cliOptions = {}) {
module.exports = async (sourceDir, cliOptions = {}, ctx) => {
const { server, host, port } = await prepareServer(sourceDir, cliOptions, ctx)
server.listen(port, host, err => {
if (err) {
console.log(err)
}
})
}

module.exports.prepare = prepareServer

async function prepareServer (sourceDir, cliOptions = {}, context) {
const WebpackDevServer = require('webpack-dev-server')
const { path } = require('@vuepress/shared-utils')
const webpack = require('webpack')
const chokidar = require('chokidar')
const serve = require('webpack-serve')
const convert = require('koa-connect')
const mount = require('koa-mount')
const range = require('koa-range')
const serveStatic = require('koa-static')
const history = require('connect-history-api-fallback')

const prepare = require('./prepare/index')
const { chalk, fs, logger } = require('@vuepress/shared-utils')
const { chalk, logger } = require('@vuepress/shared-utils')
const HeadPlugin = require('./webpack/HeadPlugin')
const DevLogPlugin = require('./webpack/DevLogPlugin')
const createClientConfig = require('./webpack/createClientConfig')
const { applyUserWebpackConfig } = require('./util/index')
const { frontmatterEmitter } = require('@vuepress/markdown-loader')

logger.wait('Extracting site metadata...')
const ctx = await prepare(sourceDir, cliOptions, false /* isProd */)
const ctx = context || await prepare(sourceDir, cliOptions, false /* isProd */)

// setup watchers to update options and dynamically generated files
const update = (reason) => {
Expand Down Expand Up @@ -105,52 +110,52 @@ module.exports = async function dev (sourceDir, cliOptions = {}) {
config = applyUserWebpackConfig(userConfig, config, false /* isServer */)
}

const serverConfig = Object.assign({
disableHostCheck: true,
Copy link
Member Author

Choose a reason for hiding this comment

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

✅Used to bypasses host checking.

compress: true,
Copy link
Member Author

Choose a reason for hiding this comment

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

✅Used to bnable gzip compression for everything served.

clientLogLevel: 'error',
hot: true,
Copy link
Member Author

Choose a reason for hiding this comment

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

✅Enable webpack's Hot Module Replacement feature.

quiet: true,
Copy link
Member Author

Choose a reason for hiding this comment

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

With devServer.quiet enabled, nothing except the initial startup information will be written to the console. This also means that errors or warnings from webpack are not visible.

❌This option shouldn't be set to true.

headers: {
'access-control-allow-origin': '*'
},
Copy link
Member Author

Choose a reason for hiding this comment

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

✅This option was set to enable CQRS.

publicPath: ctx.base,
Copy link
Member Author

Choose a reason for hiding this comment

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

publicPath of devServer should be consistent to publicPath of output option.

watchOptions: {
ignored: /node_modules/
},
Copy link
Member Author

Choose a reason for hiding this comment

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

✅Excluded such a huge folder.

historyApiFallback: {
rewrites: [
{ from: /\.html$/, to: '/' }
]
},
Copy link
Member Author

Choose a reason for hiding this comment

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

✅Follow the past configuration.

overlay: false,
Copy link
Member Author

Choose a reason for hiding this comment

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

✅Do not need to show a full-screen overlay in the browser when there are compiler errors or warnings

host,
Copy link
Member Author

Choose a reason for hiding this comment

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

contentBase: path.resolve(sourceDir, '.vuepress/public'),
before (app, server) {
ctx.pluginAPI.options.beforeDevServer.syncApply(app, server)
},
after (app, server) {
ctx.pluginAPI.options.afterDevServer.syncApply(app, server)
}
}, ctx.siteConfig.devServer || {})

WebpackDevServer.addDevServerEntrypoints(config, serverConfig)

const compiler = webpack(config)
const server = new WebpackDevServer(compiler, serverConfig)
Copy link
Member Author

Choose a reason for hiding this comment

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

❌We should create a Node.js API for dev so that plugin developers can do more things.

e.g. custom a command to export current VuePress site to a PDF.

const { dev } = require('vuepresss')

module.exports = {
  extendCli (cli) {
    cli
      .command('export [targetDir]', 'export current vuepress site to a PDF')
      .action(async (dir = '.') => {
        const { port, host, server } = await dev.prepare()
        server.listen(port, host, err => {
          if (err) {
            console.log(err)
          }
        })
        // do somthing, such as launch browser to export PDF.
        await generatePDF()

        server.close()
      })
  }
}


const nonExistentDir = path.resolve(__dirname, 'non-existent')
await serve({
// avoid project cwd from being served. Otherwise if the user has index.html
// in cwd it would break the server
content: [nonExistentDir],
compiler,
return {
server,
host,
dev: { logLevel: 'warn' },
hot: {
port: port + 1,
logLevel: 'error'
},
logLevel: 'error',
port,
open: cliOptions.open,
add: app => {
// apply plugin options to extend dev server.
ctx.pluginAPI.options.enhanceDevServer.syncApply(app)

const userPublic = path.resolve(sourceDir, '.vuepress/public')

// enable range request
app.use(range)
Copy link
Member Author

Choose a reason for hiding this comment

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

✅Express enable range request in development. so removing it will not break the fix of #555.


// respect base when serving static files...
if (fs.existsSync(userPublic)) {
app.use(mount(ctx.base, serveStatic(userPublic)))
}

app.use(convert(history({
rewrites: [
{ from: /\.html$/, to: '/' }
]
})))
}
})
ctx
}
}

function resolveHost (host) {
// webpack-serve hot updates doesn't work properly over 0.0.0.0 on Windows,
// but localhost does not allow visiting over network :/
const defaultHost = process.platform === 'win32' ? 'localhost' : '0.0.0.0'
const defaultHost = 'localhost'
host = host || defaultHost
const displayHost = host === defaultHost && process.platform !== 'win32'
const displayHost = host === defaultHost
? 'localhost'
: host
return {
Expand Down
5 changes: 3 additions & 2 deletions packages/@vuepress/core/lib/plugin-api/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const PLUGIN_OPTION_META_MAP = {
GENERATED: { name: 'generated', types: [Function], async: true },
// options
CHAIN_WEBPACK: { name: 'chainWebpack', types: [Function] },
ENHANCE_DEV_SERVER: { name: 'enhanceDevServer', types: [Function] },
ENHANCE_APP_FILES: { name: 'enhanceAppFiles', types: [String, Object, Array, Function] },
OUT_FILES: { name: 'outFiles', types: [Object] },
EXTEND_PAGE_DATA: { name: 'extendPageData', types: [Function] },
Expand All @@ -20,7 +19,9 @@ const PLUGIN_OPTION_META_MAP = {
GLOBAL_UI_COMPONENTS: { name: 'globalUIComponents', types: [String, Array] },
DEFINE: { name: 'define', types: [Function, Object] },
ALIAS: { name: 'alias', types: [Function, Object] },
EXTEND_CLI: { name: 'extendCli', types: [Function] }
EXTEND_CLI: { name: 'extendCli', types: [Function] },
BEFORE_DEV_SERVER: { name: 'beforeDevServer', types: [Function] },
AFTER_DEV_SERVER: { name: 'afterDevServer', types: [Function] }
}

const PLUGIN_OPTION_MAP = {}
Expand Down
8 changes: 5 additions & 3 deletions packages/@vuepress/core/lib/plugin-api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ module.exports = class PluginAPI {

// options
chainWebpack,
enhanceDevServer,
extendMarkdown,
chainMarkdown,
enhanceAppFiles,
Expand All @@ -207,7 +206,9 @@ module.exports = class PluginAPI {
globalUIComponents,
define,
alias,
extendCli
extendCli,
beforeDevServer,
afterDevServer
}) {
const isInternalPlugin = pluginName.startsWith('@vuepress/internal-')
logger[isInternalPlugin ? 'debug' : 'tip'](pluginLog(pluginName, shortcut))
Expand All @@ -218,7 +219,6 @@ module.exports = class PluginAPI {
.registerOption(PLUGIN_OPTION_MAP.UPDATED.key, updated, pluginName)
.registerOption(PLUGIN_OPTION_MAP.GENERATED.key, generated, pluginName)
.registerOption(PLUGIN_OPTION_MAP.CHAIN_WEBPACK.key, chainWebpack, pluginName)
.registerOption(PLUGIN_OPTION_MAP.ENHANCE_DEV_SERVER.key, enhanceDevServer, pluginName)
.registerOption(PLUGIN_OPTION_MAP.EXTEND_MARKDOWN.key, extendMarkdown, pluginName)
.registerOption(PLUGIN_OPTION_MAP.CHAIN_MARKDOWN.key, chainMarkdown, pluginName)
.registerOption(PLUGIN_OPTION_MAP.EXTEND_PAGE_DATA.key, extendPageData, pluginName)
Expand All @@ -231,6 +231,8 @@ module.exports = class PluginAPI {
.registerOption(PLUGIN_OPTION_MAP.DEFINE.key, define, pluginName)
.registerOption(PLUGIN_OPTION_MAP.ALIAS.key, alias, pluginName)
.registerOption(PLUGIN_OPTION_MAP.EXTEND_CLI.key, extendCli, pluginName)
.registerOption(PLUGIN_OPTION_MAP.BEFORE_DEV_SERVER.key, beforeDevServer, pluginName)
.registerOption(PLUGIN_OPTION_MAP.AFTER_DEV_SERVER.key, afterDevServer, pluginName)
}
}

Expand Down
2 changes: 2 additions & 0 deletions packages/@vuepress/core/lib/prepare/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
*/

const AppContext = require('./AppContext')
const { logger } = require('@vuepress/shared-utils')

/**
* Expose prepare.
*/

module.exports = async function prepare (sourceDir, cliOptions, isProd) {
logger.wait('Extracting site metadata...')
const appContext = AppContext.getInstance(sourceDir, cliOptions, isProd)
await appContext.process()
return appContext
Expand Down
4 changes: 4 additions & 0 deletions packages/@vuepress/core/lib/webpack/createClientConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ module.exports = function createClientConfig (ctx) {
mergeLonghand: false
}
}])
} else {
config
.plugin('hmr')
.use(require('webpack/lib/HotModuleReplacementPlugin'))
}

if (!env.isDebug) {
Expand Down
6 changes: 1 addition & 5 deletions packages/@vuepress/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,6 @@
"css-loader": "^0.28.11",
"file-loader": "^1.1.11",
"js-yaml": "^3.11.0",
"koa-connect": "^2.0.1",
"koa-mount": "^3.0.0",
"koa-range": "^0.3.0",
"koa-static": "^4.0.2",
"lru-cache": "^5.1.1",
"mini-css-extract-plugin": "0.4.4",
"optimize-css-assets-webpack-plugin": "^4.0.0",
Expand All @@ -65,7 +61,7 @@
"webpack": "^4.8.1",
"webpack-chain": "^4.6.0",
"webpack-merge": "^4.1.2",
"webpack-serve": "^1.0.2",
"webpack-dev-server": "^3.1.14",
"webpackbar": "^2.6.1"
},
"engines": {
Expand Down
40 changes: 17 additions & 23 deletions packages/docs/docs/plugin/option-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,42 +132,36 @@ module.exports = (options, context) => ({
})
```

## enhanceDevServer
## beforeDevServer

- Type: `Function`
- Default: undefined

Enhance the underlying [Koa](https://github.com/koajs/koa) app.
Equivalent to [before](https://webpack.js.org/configuration/dev-server/#devserver-before) in [webpack-dev-server](https://github.com/webpack/webpack-dev-server). you can use it to define custom handlers before all middleware is executed:

``` js
```js
module.exports = {
enhanceDevServer (app) {
// ...
// ...
beforeDevServer(app, server) {
app.get('/path/to/your/custom', function(req, res) {
res.json({ custom: 'response' })
})
}
}
```

A simple plugin to create a sub public directory is as follows:
## afterDevServer

```js
const path = require('path')
- Type: `Function`
- Default: undefined

module.exports = (options, context) => {
const imagesAssetsPath = path.resolve(context.sourceDir, '.vuepress/images')
Equivalent to [after](https://webpack.js.org/configuration/dev-server/#devserver-after) in [webpack-dev-server](https://github.com/webpack/webpack-dev-server). you can use it to execute custom middleware after all other middleware:

return {
// For development
enhanceDevServer (app) {
const mount = require('koa-mount')
const serveStatic = require('koa-static')
app.use(mount(path.join(context.base, 'images'), serveStatic(imagesAssetsPath)))
},

// For production
async generated () {
const { fs } = require('@vuepress/shared-utils')
await fs.copy(imagesAssetsPath, path.resolve(context.outDir, 'images'))
}
```js
module.exports = {
// ...
afterDevServer(app, server) {
// hacking now ...
}
}
```
Expand Down
40 changes: 17 additions & 23 deletions packages/docs/docs/zh/plugin/option-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,42 +136,36 @@ module.exports = (options, context) => ({
})
```

## enhanceDevServer
## beforeDevServer

- 类型: `Function`
- 默认值: undefined

拓展 devServer 下层的 [Koa](https://github.com/koajs/koa) app
等同于 [webpack-dev-server](https://github.com/webpack/webpack-dev-server) 中的 [before](https://webpack.js.org/configuration/dev-server/#devserver-before) 选项,你可以使用它来自定义你的 devServer,如

``` js
```js
module.exports = {
enhanceDevServer (app) {
// ...
// ...
beforeDevServer(app, server) {
app.get('/path/to/your/custom', function(req, res) {
res.json({ custom: 'response' })
})
}
}
```

一个简单的创建子 public 目录的插件如下:
## afterDevServer

```js
const path = require('path')
- 类型: `Function`
- 默认值: undefined

module.exports = (options, context) => {
const imagesAssetsPath = path.resolve(context.sourceDir, '.vuepress/images')
等同于 [webpack-dev-server](https://github.com/webpack/webpack-dev-server) 中的 [after](https://webpack.js.org/configuration/dev-server/#devserver-after),你可以用其在所有中间件的最后去执行一些自定义的中间件:

return {
// For development
enhanceDevServer (app) {
const mount = require('koa-mount')
const serveStatic = require('koa-static')
app.use(mount(path.join(context.base, 'images'), serveStatic(imagesAssetsPath)))
},

// For production
async generated () {
const { fs } = require('@vuepress/shared-utils')
await fs.copy(imagesAssetsPath, path.resolve(context.outDir, 'images'))
}
```js
module.exports = {
// ...
afterDevServer(app, server) {
// hacking now ...
}
}
```
Expand Down
File renamed without changes.
1 change: 1 addition & 0 deletions packages/vuepress/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('@vuepress/core')
4 changes: 2 additions & 2 deletions packages/vuepress/lib/handleUnknownCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module.exports = async function (cli, options) {

if (sourceDir) {
context = await prepare(sourceDir, options)
context.pluginAPI.options.extendCli.apply(cli)
context.pluginAPI.options.extendCli.apply(cli, context)
}

logger.setOptions({ logLevel: 3 })
Expand Down Expand Up @@ -107,7 +107,7 @@ function registerUnknownCommands (cli, options) {
...options,
...commandoptions
}, false /* isProd */)
await context.pluginAPI.options.extendCli.apply(subCli)
await context.pluginAPI.options.extendCli.apply(subCli, context)
},
async afterParse (subCli) {
if (!subCli.matchedCommand) {
Expand Down
4 changes: 2 additions & 2 deletions packages/vuepress/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "vuepress",
"version": "1.0.0-alpha.32",
"description": "Minimalistic doc generator with Vue component based layout system",
"main": "vuepress.js",
"main": "index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/vuejs/vuepress.git"
Expand All @@ -13,7 +13,7 @@
"generator"
],
"bin": {
"vuepress": "vuepress.js"
"vuepress": "cli.js"
},
"author": "Evan You",
"maintainers": [
Expand Down
Loading