关于Vue单页面骨架屏实践记录(2)

当然这里的skeleton.vue使我们事先写好的骨架屏组件,看起来可能是这样:

 <template>
 <div class="skeleton-wrapper">
 <header class="skeleton-header"></header>
 <div class="skeleton-block"></div>
 </div>
</template>

然后我们需要的是能把skeleton.entry.js编译成服务端渲染可用的bundle文件,所以我们需要有个编译骨架屏的webpack.ssr.conf.js文件:

const path = require('path');
const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf');
const nodeExternals = require('webpack-node-externals');
function resolve(dir) {
 return path.join(__dirname, dir);
}
module.exports = merge(baseWebpackConfig, {
 target: 'node',
 devtool: false,
 entry: {
 app: resolve('./src/skeleton.entry.js')
 },
 output: Object.assign({}, baseWebpackConfig.output, {
 libraryTarget: 'commonjs2'
 }),
 externals: nodeExternals({
 whitelist: /\.css$/
 }),
 plugins: []
});

接下来最终的步骤,就是编写我们的webpackPlugin,我们期望我们的webpackPlugin可以帮我们把入口文件编译成bundle,然后再通过vue-server-renderer来render bundle,最终产出响应的html片段和css片段,这里贴出核心代码:

 // webpack start to work
 var serverCompiler = webpack(serverWebpackConfig);
 var mfs = new MFS();
 // output to mfs
 serverCompiler.outputFileSystem = mfs;
 serverCompiler.watch({}, function (err, stats) {

 if (err) {
  reject(err);
  return;
 }
 stats = stats.toJson();
 stats.errors.forEach(function (err) {
  console.error(err);
 });
 stats.warnings.forEach(function (err) {
  console.warn(err);
 });
 var bundle = mfs.readFileSync(outputPath, 'utf-8');
 var skeletonCss = mfs.readFileSync(outputCssPath, 'utf-8');
 // create renderer with bundle
 var renderer = createBundleRenderer(bundle);
 // use vue ssr to render skeleton
 renderer.renderToString({}, function (err, skeletonHtml) {
  if (err) {
  reject(err);
  }
  else {
  resolve({skeletonHtml: skeletonHtml, skeletonCss: skeletonCss});
  }
 });
 });

最后一步,我们对产出的html片段, css片段进行组装,产出最终的html,所以我们需要监听webpack 的编译挂载之前的事件:

compiler.plugin('compilation', function (compilation) {
 // add listener for html-webpack-plugin
 compilation.plugin('html-webpack-plugin-before-html-processing', function (htmlPluginData, callback) {
 ssr(webpackConfig).then(function (ref) {
  var skeletonHtml = ref.skeletonHtml;
  var skeletonCss = ref.skeletonCss;
  // insert inlined styles into html
  var headTagEndPos = htmlPluginData.html.lastIndexOf('</head>');
  htmlPluginData.html = insertAt(htmlPluginData.html, ("<style>" + skeletonCss + "</style>"), headTagEndPos);

  // replace mounted point with ssr result in html
  var appPos = htmlPluginData.html.lastIndexOf(insertAfter) + insertAfter.length;
  htmlPluginData.html = insertAt(htmlPluginData.html, skeletonHtml, appPos);
  callback(null, htmlPluginData);
 });
 });
 }); 
      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/635.html