Open mahatma-andy opened 5 years ago
I managed to set it up. Yeah, this plugin serves from the root of staticDir
, no matter what publicPath
is. So my solution was to make Webpack write files to publicPath
inside of ./dist
, not to its root.
At the top of my webpack.prod.conf:
const PUBLIC_PATH = process.env.PUBLIC_PATH || "/";
if (!PUBLIC_PATH.startsWith("/")) {
console.error("Please, use an absolute PUBLIC_PATH");
process.exit(1);
} else if (!PUBLIC_PATH.endsWith("/")) {
console.error("PUBLIC_PATH should end in '/'");
process.exit(1);
}
const filePath = path.resolve(__dirname, "dist", PUBLIC_PATH.substr(1));
In Webpack config:
output: {
path: filePath,
filename: "js/[name].[contenthash:8].js",
publicPath: PUBLIC_PATH,
chunkFilename: "js/[name].[contenthash:8].js"
},
And config for this plugin:
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, "dist"),
indexPath: path.resolve(filePath, "index.html"),
routes: [ "", "about", "help" ].map(x => PUBLIC_PATH + x),
renderer: new Renderer({
inject: {},
headless: true,
renderAfterDocumentEvent: "render-event"
})
})
This way Webpack writes your files to ./dist/<publicPath>
, and PrerenderSPAPlugin serves from ./dist
, using an index file located at ./dist/<publicPath>/index.html
. It then visits pages <publicPath>
, <publicPath>about
, <publicPath>help
.
E. g. your public path is /vue/
. Then Webpack writes files to ./dist/vue/
, and prerender starts a webserver with root in ./dist/
, but using the ./dist/vue/index.html
file as fallback. It then goes to 127.0.0.1/vue/, 127.0.0.1/vue/about, 127.0.0.1/vue/help and saves them.
If my publish path is a CDN domain name like 'https://test.com/', how can I solve this problem? Please. I would like put bundled package like js and css on Cloud Storage and use CDN to speed up my website. And the first page I would like to use prerendering. @26000
@Yzzzed unfortunately, I don't think it's possible to use a public path with your domain name when prerendering. If you specify an absolute URL as publicPath
, your index.html
will try to load js/css/etc files from your production server, not your local directory. As they don't yet exist on the server, it'll just fail.
An easy, but hacky solution may be to first upload the files to your server as needed, and then use some other prerender tool on the live instance of your code. Or you could try to specify a relative URL as your publicPath
and then replace all the links in prerendered files with absolute ones, but this too is a dirty hack and it would probably be hard to make it work correctly.
thx. I also think it is a dirty way, haha. Maybe I will try to find another one. @26000
@26000 i Want to put it in the nginx secondary directory after packaging Follow your guide, prompt this : "Error: ENOENT: no such file or directory, stat 'd:\testspace\proj-hyt-web-prerender\examples\vue2-webpack-router\dist\cn\index.html'"
webpack.config.js `var path = require('path') var webpack = require('webpack') var HtmlWebpackPlugin = require('html-webpack-plugin') const PrerenderSPAPlugin = require('prerender-spa-plugin') const Renderer = PrerenderSPAPlugin.PuppeteerRenderer const VueLoaderPlugin = require('vue-loader/lib/plugin')
const PUBLIC_PATH = process.env.PUBLIC_PATH || "/"; if (!PUBLIC_PATH.startsWith("/")) { console.error("Please, use an absolute PUBLIC_PATH"); process.exit(1); } else if (!PUBLIC_PATH.endsWith("/")) { console.error("PUBLIC_PATH should end in '/'"); process.exit(1); }
const filePath = path.resolve(__dirname, "dist", PUBLIC_PATH.substr(1));
module.exports = { mode: process.env.NODE_ENV, entry: './src/main.js', output: { path: path.resolve(dirname, './dist'), publicPath: PUBLIC_PATH, filename: 'js/[name].[contenthash:8].js', chunkFilename: "js/[name].[contenthash:8].js" }, module: { rules: [ { test: /.vue$/, loader: 'vue-loader' }, { test: /.js$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /.(png|jpg|gif|svg)$/, loader: 'file-loader', options: { name: '[name].[ext]?[hash]' } }, { test: /.css$/, use: [ 'vue-style-loader', 'css-loader' ] } ] }, resolve: { alias: { 'vue$': 'vue/dist/vue.esm.js' } }, devServer: { historyApiFallback: true, noInfo: false, }, devtool: '#eval-source-map', plugins: [ new VueLoaderPlugin(), ] } if (process.env.NODE_ENV === 'production') { module.exports.devtool = '#source-map' module.exports.plugins = (module.exports.plugins || []).concat([ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"production"' } }), new HtmlWebpackPlugin({ title: 'PRODUCTION prerender-spa-plugin', template: 'index.html', filename: path.resolve(dirname, 'dist/index.html'), favicon: 'favicon.ico' }), new PrerenderSPAPlugin({ staticDir: path.join(__dirname, "dist"), indexPath: path.resolve(filePath, "index.html"), routes: [ '/', '/about', '/contact' ].map(x => PUBLIC_PATH + x),
renderer: new Renderer({
inject: {
foo: 'bar'
},
headless: true,
renderAfterDocumentEvent: 'render-event'
})
})
]) } else { // NODE_ENV === 'development' module.exports.plugins = (module.exports.plugins || []).concat([ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"development"' } }), new HtmlWebpackPlugin({ title: 'DEVELOPMENT prerender-spa-plugin', template: 'index.html', filename: 'index.html', favicon: 'favicon.ico' }), ]) }`
If you would like to serve the Vue app for subdirectory /vue
(https://example.com/vue), you should specify not only publicPath, but also outputDir, staticDir, and indexPath as follows:
dist/vue
dist
dist/vue/index.html
const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
module.exports = {
publicPath: '/vue/',
outputDir: 'dist/vue/',
configureWebpack: () => {
if (process.env.NODE_ENV === 'production') {
return {
plugins: [
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'),
indexPath: path.join(__dirname, 'dist/vue/index.html'),
['/vue', '/vue/vps', '/vue/contact']
]
}
}
}
}
If you set the publicPath
(generally, it's a cdn resource address), should confirm that when prerender process happen, the prerenderer can access the assets by the publicPath
.
So, one way to solve this problem is:
Seems a little gross, but simple enough, and works for me.
If you would like to serve the Vue app for subdirectory
/vue
(https://example.com/vue), you should specify not only publicPath, but also outputDir, staticDir, and indexPath as follows:
- outputDir is
dist/vue
- routes includes the subdirectory like ['/vue', '/vue/vps', '/vue/contact', ...]
- staticDir is
dist
- indexPath is
dist/vue/index.html
const path = require('path') const PrerenderSPAPlugin = require('prerender-spa-plugin') module.exports = { publicPath: '/vue/', outputDir: 'dist/vue/', configureWebpack: () => { if (process.env.NODE_ENV === 'production') { return { plugins: [ new PrerenderSPAPlugin({ staticDir: path.join(__dirname, 'dist'), indexPath: path.join(__dirname, 'dist/vue/index.html'), ['/vue', '/vue/vps', '/vue/contact'] ] } } } }
You can add another line Make it work better
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'),
outputDir: path.join(__dirname, '/dist/vue/'),
indexPath: path.join(__dirname, 'dist/vue/index.html'),
['/vue', '/vue/vps', '/vue/contact']
})
I've installed this plugin to pre-render my Vue project, which uses vue-router (in history mode) and Webpack.
The Vue app is not in the root directory of the server serving it. It is in a subdirectory of that server (specifically, /vue, meaning it is served from /vue/dist).
When
publicPath: '/vue/dist',
invue.config.js
, the plugin only pre-renders around the parent<router-view />
component. If I changepublicPath: '/',
, the markup for each route is pre-rendered as expected.This is what my
vue.config.js
file looks like:It looks as if the pre-renderer is not passed the
publicPath
, but I am not confident in saying that. I would like to know whether there is a way to pass thepublicPath
parameter to the pre-renderer, and if so, what it is. I've looked through the open and closed issues on this project, but the suggestions I found assume that the server root is one within the app's base directory. In my case, it is outside this directory.