vue预渲染 render-spa-plugin
-
全局安装
npm install -g @vue/cli-init
-
创建vebpack项目
vue init webpack . // 在当前文件夹下创建项目
? Generate project in current directory? Yes ? Project name prerender-spa ? Project description A Vue.js project ? Author dxc1996 <18895364886@163.com> ? Vue build standalone ? Install vue-router? Yes ? Use ESLint to lint your code? No ? Set up unit tests No ? Setup e2e tests with Nightwatch? No ? Should we run `npm install` for you after the project has been created? (recommended) npm
-
安装插件
npm/cnpm i prerender-spa-plugin -D
-
路由模式要为
history
import Vue from 'vue' import Router from 'vue-router' import Home from '@/components/Home' import About from '@/components/About' import Test from '@/components/Test' Vue.use(Router) export default new Router({ mode:'history', routes: [ {path: '/',name: 'Home',component: Home}, {path: '/about',name: 'About',component: About}, {path: '/test',name: 'Test',component: Test} ] })
这是我的目录结构
-
在webpack.prod.config.js下配置
const PrerenderSPAPlugin = require('prerender-spa-plugin'); // 调用渲染器 const Renderer = PrerenderSPAPlugin.PuppeteerRenderer plugins:[ ... //调用渲染器 new PrerenderSPAPlugin({ staticDir: path.join(__dirname, '../dist'), // Required - Routes to render. routes: [ '/', '/about'], renderer: new Renderer({ inject: { foo: 'bar' }, headless: false, // 在项目的入口使用document.dispatchEvent(new Event('render-event')) renderAfterDocumentEvent: 'render-event', }) }) ]
整体来说是这样的
'use strict' const path = require('path') const utils = require('./utils') const webpack = require('webpack') const config = require('../config') const merge = require('webpack-merge') const baseWebpackConfig = require('./webpack.base.conf') const CopyWebpackPlugin = require('copy-webpack-plugin') const HtmlWebpackPlugin = require('html-webpack-plugin') const ExtractTextPlugin = require('extract-text-webpack-plugin') const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') const UglifyJsPlugin = require('uglifyjs-webpack-plugin') const PrerenderSPAPlugin = require('prerender-spa-plugin'); // 调用渲染器 const Renderer = PrerenderSPAPlugin.PuppeteerRenderer const env = require('../config/prod.env') const webpackConfig = merge(baseWebpackConfig, { module: { rules: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true, usePostCSS: true }) }, devtool: config.build.productionSourceMap ? config.build.devtool : false, output: { path: config.build.assetsRoot, filename: utils.assetsPath('js/[name].[chunkhash].js'), chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') }, plugins: [ // http://vuejs.github.io/vue-loader/en/workflow/production.html new webpack.DefinePlugin({ 'process.env': env }), new UglifyJsPlugin({ uglifyOptions: { compress: { warnings: false } }, sourceMap: config.build.productionSourceMap, parallel: true }), // extract css into its own file new ExtractTextPlugin({ filename: utils.assetsPath('css/[name].[contenthash].css'), // Setting the following option to `false` will not extract CSS from codesplit chunks. // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110 allChunks: true, }), // Compress extracted CSS. We are using this plugin so that possible // duplicated CSS from different components can be deduped. new OptimizeCSSPlugin({ cssProcessorOptions: config.build.productionSourceMap ? { safe: true, map: { inline: false } } : { safe: true } }), // generate dist index.html with correct asset hash for caching. // you can customize output by editing /index.html // see https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: config.build.index, template: 'index.html', inject: true, minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true // more options: // https://github.com/kangax/html-minifier#options-quick-reference }, // necessary to consistently work with multiple chunks via CommonsChunkPlugin chunksSortMode: 'dependency' }), // keep module.id stable when vendor modules does not change new webpack.HashedModuleIdsPlugin(), // enable scope hoisting new webpack.optimize.ModuleConcatenationPlugin(), // split vendor js into its own file new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks (module) { // any required modules inside node_modules are extracted to vendor return ( module.resource && /\.js$/.test(module.resource) && module.resource.indexOf( path.join(__dirname, '../node_modules') ) === 0 ) } }), // extract webpack runtime and module manifest to its own file in order to // prevent vendor hash from being updated whenever app bundle is updated new webpack.optimize.CommonsChunkPlugin({ name: 'manifest', minChunks: Infinity }), // This instance extracts shared chunks from code splitted chunks and bundles them // in a separate chunk, similar to the vendor chunk // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk new webpack.optimize.CommonsChunkPlugin({ name: 'app', async: 'vendor-async', children: true, minChunks: 3 }), // copy custom static assets new CopyWebpackPlugin([ { from: path.resolve(__dirname, '../static'), to: config.build.assetsSubDirectory, ignore: ['.*'] } ]), //调用渲染器 new PrerenderSPAPlugin({ // Required - The path to the webpack-outputted app to prerender. staticDir: path.join(__dirname, '../dist'), // Required - Routes to render. routes: [ '/', '/about'], renderer: new Renderer({ // Optional - Any values you'd like your app to have access to via `window.injectProperty`. inject: { foo: 'bar' }, // Other puppeteer options. // (See here: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions) headless: false, // Display the browser window when rendering. Useful for debugging. // Optional - Wait to render until the specified event is dispatched on the document. // eg, with `document.dispatchEvent(new Event('custom-render-trigger'))` // 在项目的入口使用document.dispatchEvent(new Event('render-event')) renderAfterDocumentEvent: 'render-event', }) }) ] }) if (config.build.productionGzip) { const CompressionWebpackPlugin = require('compression-webpack-plugin') webpackConfig.plugins.push( new CompressionWebpackPlugin({ asset: '[path].gz[query]', algorithm: 'gzip', test: new RegExp( '\\.(' + config.build.productionGzipExtensions.join('|') + ')$' ), threshold: 10240, minRatio: 0.8 }) ) } if (config.build.bundleAnalyzerReport) { const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin webpackConfig.plugins.push(new BundleAnalyzerPlugin()) } module.exports = webpackConfig
-
配置main.js
new Vue({ el: '#app', router, components: { App }, template: '<App/>', mounted(){ document.dispatchEvent(new Event('render-event')) } })
-
打包后的文件
如有雷同,请联系删除