记录webpack插件的使用---静态资源gzip和打包出静态页面优化SEO

544 阅读3分钟

本文记录优化线上项目使用到的webpack插件(compression-webpack-pluginprerender-spa-plugin),已使用到正式项目中,可戳 简点活动 查看效果

一. 大哥:项目打包出来的js,css太大了,你用Gzip优化一下吧。

image.png

那就来呗

项目使用vue2开发,功能不多,但是打包出来已经有2.6M了。使用gzip试试能优化到什么地步:

1.安装依赖:
npm install compression-webpack-plugin -D
2.修改vue.config.js
...//省略
const CompressionPlugin = require('compression-webpack-plugin')
module.exports = {
    ...,
    configureWebpack: config => {
        if (NODE_ENV === 'production') {
            return {
                plugins: [
                        new CompressionPlugin({
                        test: /\.js$|\.html$|\.css/, //匹配文件名
                        threshold: 10240, //对超过10K的数据进行压缩
                        deleteOriginalAssets: false //是否删除原文件
                    }),
                    new webpack.optimize.MinChunkSizePlugin({
                        minChunkSize: 10000 // 通过合并小于 minChunkSize 大小的 chunk,将 chunk 体积保持在指定大小限制以上
                    }),
                ]
            }
        }
}

3.重新编译,查看效果

优化前: 微信截图_20220729163043.png 优化后:

微信截图_20220729163058.png 对比可发现降低到原来的3/10,优化效果明显。css压缩效果更明显,大概为原来的1.4/10

微信截图_20220729163902.png

image.png

4. nginx配置支持gzip,nginx中http块里面增加一行:
http{
     ...
     gzip_static         on;
     server{
        ...
     }    
}

重新打开页面,看到如下图说明配置成功

image.png

查看瀑布流可看到确实加载的是压缩后的gz文件大小

image.png

image.png

二. 大哥:Vue打包出来的页面都是通过js渲染的,首页SEO太差了,你去找找有什么办法可以解决。

image.png

大佬一句话,小弟跑断腿。本来想着是直接通过新建一个html将浏览器渲染的内容拷贝出来,但是这方法不太灵活,重新打包后css和js会改变,需要再操作一次,如果有自动帮我们处理这活的插件就好了(狗头)。

一番搜索后找到一个插件 prerender-spa-plugin。该插件可在打包后自动打开一个谷歌浏览器,开启一个静态资源服务器,加载打包后的网站。将配置的routes页面打开并拷贝页面渲染完毕的dom结构,生成对应的静态html。

image.png

下面展示具体使用方法:

1. 安装依赖,此处会安装一个chrome依赖,时间有点久

cnpm i prerender-spa-plugin -D

2.配置vue.config.js

const PrerenderSPAPlugin = require('prerender-spa-plugin');
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;

module.exports = {
    ...
    configureWebpack: config => {
        if (NODE_ENV === 'production') {
            return {
                plugins: [
                    
                    new PrerenderSPAPlugin({
                        // 生成文件的路径,也可以与webpakc打包的一致。
                        // 下面这句话非常重要!!!
                        // 这个目录只能有一级,如果目录层次大于一级,在生成的时候不会有任何错误提示,在预渲染的时候只会卡着不动。
                        staticDir: path.join(__dirname, 'dist'),
                        // 对应自己的路由文件,比如a有参数,就需要写成 /a/param1。
                        routes: ['/index'],
                        // 这个很重要,如果没有配置这段,也不会进行预编译
                        renderer: new Renderer({
                            inject: {
                                foo: 'bar'
                            },
                            headless: false,
                            // 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。
                            renderAfterDocumentEvent: 'render-event'
                        })
                    }),
                ]
            }
        } 
    },
}

3.main.js 修改

new Vue({
  router,
  store,
  render: (h) => h(App),
  // 预渲染
  mounted() {
    document.dispatchEvent(new Event('render-event'))
  }
}).$mount('#app');

4.打包 npm run build 后可以看到dist目录下生成了一个index文件夹,里面有个index.html,首页的所有静态内容以及css,js都正确的被引入,内容如下:

image.png

发布到线上访问,查看源码可以看到已经有了所有的静态内容,接口请求填充内容也没问题。

完结撒花

image.png

补充1. 如果项目中使用了cdn存放静态资源,需要如下配置:

使用了cdn,打包后由于还没将css,js上传到cdn,这时候访问html是展示不了的,会出现问题,需要改下vue.config.js

...
const cdnPath = '//cdn.xxx.com/static'
export.defualt = {
    publicPath: '/', // 原来是cdn地址
    ...
        new PrerenderSPAPlugin({
            staticDir: path.join(__dirname, 'dist'),
            // 对应自己的路由文件,比如a有参数,就需要写成 /a/param1。
            routes: ['/index'],
            postProcess (renderedRoute) {
              // add CDN
              renderedRoute.html = renderedRoute.html.replace(
                /(<script[^<>]*src=\")((?!http|https)[^<>\"]*)(\"[^<>]*>[^<>]*<\/script>)/ig, `$1${cdnPath}$2$3` )
                .replace( /(<link[^<>]*href=\")((?!http|https)[^<>\"]*)(\"[^<>]*>)/ig, `$1${cdnPath}$2$3` ) 
                return renderedRoute 
            }, 
            renderer: new Renderer({ 
                injectProperty: '__PRERENDER_INJECTED__', 
                inject: 'prerender',
                headless: false,
                // 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。
                renderAfterDocumentEvent: 'render-event'
            }) 
        })
}

打包之后由于publicPath为/,生成的index.html加载的js和css路径也为/开头,需要替换一下,创建一个replaceCdn.js,将index.html的资源路径正确引用。

const fs = require('fs')
const path = require('path')
const cdnPath = '//cdn.xxx.com/static'

const htmlStream = fs.readFileSync(path.resolve('','dist/index.html'))
let html = htmlStream.toString('utf-8')

html = html.replace(/\/static\/js/g, `${cdnPath}/js`).replace(/\/static\/css/g,  `${cdnPath}/css`)
fs.writeFileSync(path.resolve('','dist/index.html'), html)

打包成功后执行node replaceCdn.js,成功替换路径。

补充2. 如果使用Linux构建项目,可能会出现: Failed to launch chrome 错误

可删除配置中的headless:false 这行试试,如果还不行可参考:github.com/chrisvfritz…

有时候是由于Linux系统中缺少一些依赖,需要手动安装依赖,类似

image.png 解决方法参考: image.png

sudo apt-get install gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget

一些系统没有apt-get,可用 yum 安装依赖,如报找不到对应的依赖可直接搜索对应的依赖要安装哪个版本,我遇到的找不到的依赖有如下:

CentOS 7 chrome: error while loading shared libraries: libatk-bridge-2.0.so.0 解决办法 shipengliang.com/software-ex…

centos7 安装火狐浏览器出现 CentOS libgtk-3.so.0 和 libXt.so.6 缺少 blog.csdn.net/qq_35322167…