热模块重新加载使初始页面请求需要10-20秒,Webpack,Koa,Vue.js

时间:2016-10-11 06:11:21

标签: node.js webpack localhost koa webpack-hmr

由于某些原因,大多数页面刷新都会重新请求bundle.js文件,从localhost下载大约需要10-15-20秒。这一切都来自localhost,而bundle.js文件的大小约为1mb。对此文件的请求似乎只是爬行,一次加载几千字节。

一些观察结果:

  • 经过一些挖掘后,它似乎停止了从__webpack_hmr对服务器的初始调用,但是我不确定在调用bundle.js之后这个调用是否发生。以下是服务器请求流的日志。

  • 只有具有一个或两个以上组件的页面才会很慢,即。主页以外的任何内容。这暗示了它可能与热模块重新加载有关。

  • 主页仍将采用> 5s(有时是10-20)就像其他页面一样,但如果我用Ctrl + R刷新页面,它几乎立即回来。如果我进行地址栏刷新,则需要更长时间。如果我按Ctrl + R或执行地址栏重新加载,其他页面仍然需要一段时间...
  • 更新:我删除了热模块更换,它肯定是问题的根源,因为页面会在没有它的情况下立即加载。

请求日志:

  

- 响应时间GET / = 609ms
   - > GET / 200 647ms 2.55kb
  < - GET /main.aafc9fb7f6a0c7f127edb04734d29547.css
   - > GET /main.aafc9fb7f6a0c7f127edb04734d29547.css 200 17ms 3.43kb
  < - /bundle.js
   - > GET /bundle.js 200 18ms 1.29mb
  < - GET / __ webpack_hmr

然后在Chrome控制台中,对于此请求,它显示: enter image description here

这是我的设置:

  • 使用Koa作为服务器环境(在初始响应中使用流/分块)
  • 使用带热模块重新加载的webpack
  • 使用Vue.js作为前端框架,使用服务器端呈现
  • bundle.js通过典型的serve-static包提供
  • bundle.js似乎根本没有被缓存。这是为什么?

在Koa方面,我开始使用一些样板包来完成所有这些服务器端渲染等。自从我开始讨论这个设置和webpack以来,这种情况一直在发生,所以我试图深入了解它。它似乎有点随机,有时它会回来< 1s,但大多数情况下需要10秒以上。有时30多秒?!

我也尝试使用不同的库来提供静态文件,但它们似乎都是这样做的。

这是我的主要webpack配置('webpack.client',扩展如下):

'use strict'
const path = require('path')
const webpack = require('webpack')
const AssetsPlugin = require('assets-webpack-plugin')
const assetsPluginInstance = new AssetsPlugin({path: path.join(process.cwd(), 'build')})
const postcss = [
  require('precss')()
  //require('autoprefixer')({browsers: ['last 2 versions']}),
]

module.exports = {
  entry: [
    './src/client-entry.js'
  ],
  output: {
    path: path.join(process.cwd(), 'build'),
    filename: 'bundle.js',
    publicPath: '/'
  },
  resolve: {
    extensions: ['', '.vue', '.js', '.json']
  },
  module: {
    loaders: [
      {
        test: /\.vue$/,
        loaders: ['vue']
      },
      {
        test: /\.js$/,
        loaders: ['babel'],
        exclude: [/node_modules/]
      },
      {
        test: /\.json$/,
        loaders: ['json'],
        exclude: [/node_modules/]
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        loader: 'url?limit=10000&name=images/[hash].[ext]',
        include: path.src,
      },
      {
        test: /\.woff($|\?)|\.woff2($|\?)|\.ttf($|\?)|\.eot($|\?)|\.svg($|\?)/,
        loader: 'url-loader',
        include: path.src,
      }
    ]
  },
  node: { net: 'empty', dns: 'empty' },
  postcss,
  vue: {
    postcss,
    loaders: {}
  },
  plugins: [
    assetsPluginInstance
  ]
}

还有这个(扩展了前一个):

'use strict'
const webpack = require('webpack')
const config = require('./webpack.client')
const ExtractTextPlugin = require('extract-text-webpack-plugin')

config.entry.push('webpack-hot-middleware/client')
//config.devtool = 'inline-eval-cheap-source-map'
config.plugins = config.plugins.concat([
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NoErrorsPlugin(),
  new webpack.DefinePlugin({
    '__DEV__': true,
    'process.env.NODE_ENV': JSON.stringify('development')
  }),
  new ExtractTextPlugin('[name].[contenthash].css')
])
config.vue.loaders = {
  postcss: ExtractTextPlugin.extract(
    'vue-style-loader',
    'css-loader?sourceMap'
  ),
  css: ExtractTextPlugin.extract(
    'vue-style-loader',
    'css-loader?sourceMap'
  )
}

module.exports = config

这是Koa的服务器index.js文件:

import path from 'path'
import fs from 'fs'
import Koa from 'koa'
import convert from 'koa-convert'
//import serve from 'koa-static-server'
import serveStatic from 'koa-static'
import {PassThrough} from 'stream'
import {createBundleRenderer} from 'vue-server-renderer'
import serialize from 'serialize-javascript'
import MFS from 'memory-fs'
import assets from '../build/webpack-assets'
import cookie from 'koa-cookie'

let renderer
const createRenderer = fs => {
  const bundlePath = path.resolve(process.cwd(), 'build/server-bundle.js')
  return createBundleRenderer(fs.readFileSync(bundlePath, 'utf-8'))
}

const app = new Koa();

app.use(cookie());

if (process.env.NODE_ENV === 'development') {
  // DEVELOPMENT, with hot reload
  const webpack = require('webpack')
  const webpackConfig = require('../config/webpack.client.dev')
  const compiler = webpack(webpackConfig)
  const devMiddleware = require('koa-webpack-dev-middleware')
  const hotMiddleware = require('koa-webpack-hot-middleware')

  app.use(convert(devMiddleware(compiler, {
    publicPath: webpackConfig.output.publicPath,
    stats: {
      colors: true,
      modules: false,
      children: false,
      chunks: false,
      chunkModules: false
    }
  })))

  app.use(convert(hotMiddleware(compiler)))

  // server renderer
  const serverBundleConfig = require('../config/webpack.bundle')
  const serverBundleCompiler = webpack(serverBundleConfig)
  const mfs = new MFS()

  serverBundleCompiler.outputFileSystem = mfs
  serverBundleCompiler.watch({}, (err, stats) => {
    if (err) throw err
    stats = stats.toJson()
    stats.errors.forEach(err => console.error(err))
    stats.warnings.forEach(err => console.warn(err))
    renderer = createRenderer(mfs)
  })
} 
else {
  // PRODUCTION
  // use nginx to serve static files in real
  //app.use(convert(serve({rootDir: path.join(process.cwd(), 'build'), rootPath: '/static'})))
  app.use(serveStatic(path.join(process.cwd(), 'build')));
  renderer = createRenderer(fs)
}

app.use(ctx => {
  var start = new Date;
  ctx.type = 'text/html; charset=utf-8'
  const context = {url: ctx.url}
  const title = 'Tripora';
  const stream = new PassThrough()

  console.log("Checking if server-side cookie exists...");
  // See if request sent over an authentication token in their cookies
  if(ctx.cookie && ctx.cookie.token) {
    console.log("Found cookie token.");
    context.token = ctx.cookie.token;
  }

  stream.write(`<!DOCTYPE html><html style="min-height: 100%;"><head><meta charset="utf-8"/><title>${title}</title>${assets.main.css ? `<link rel="stylesheet" href="${assets.main.css}"/>` : ''}</head><body style="min-height: 100%;">`)

  const renderStream = renderer.renderToStream(context)
  let firstChunk = true

  renderStream.on('data', chunk => {
    // we tell the request to ignore files as an initial reuqest
    var isPage = ctx.url.split(".").length == 1;

    if (firstChunk && context.initialState && isPage) { 
      stream.write(`<script>window.__INITIAL_STATE__=${serialize(context.initialState, {isJSON: true})}</script>${chunk}`)
      firstChunk = false
    } else {
      stream.write(chunk)
    }
  })

  renderStream.on('end', () => {
    stream.write(`<script src="${assets.main.js}"></script></body></html>`)

    var ms = new Date - start;
    //ctx.set('X-Response-Time', ms + 'ms');
    console.log("-- Response time %s %s = %sms", ctx.method, ctx.originalUrl, ms);

    ctx.res.end()
  })

  renderStream.on('error', err => {
    console.log("ERROR", err.stack);
    throw new Error(`something bad happened when renderToStream: ${err}`)
  })

  ctx.status = 200
  ctx.body = stream
})

const port = process.env.NODE_PORT || 80
app.listen(port, () => {
  console.log(`==> Listening at http://localhost:${port}`)
})

任何人都知道为什么HMR初始请求需要这么长时间,而且似乎是随机的(有时是5秒,有时是30秒)? Techneregy。

0 个答案:

没有答案