• vue-hackernews-2.0 升级到 webpack4 和 nodejs14 的坑(下)


    概述

    最近非常想做一个服务端渲染项目,那就打算从尤大的vue-hackernews-2.0开始入手呗。其实我之前试图改造过这个项目,但是因为当时很菜所以失败了。现在我觉得有能力改造好,那就开始呗。把心得记录下来,供以后开发时参考,相信对其他人也有用。

    上篇:vue-hackernews-2.0 升级到 webpack4 和 nodejs14 的坑(上)

    CommonsChunkPlugin

    老项目是使用 commonchunksplugin 抽取公共模块和css模块的,代码如下:

    // extract vendor chunks for better caching
    new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor',
        minChunks: function (module) {
        // a module is extracted into the vendor chunk if...
        return (
            // it's inside node_modules
            /node_modules/.test(module.context) &&
            // and not a CSS file (due to extract-text-webpack-plugin limitation)
            !/.css$/.test(module.request)
        )
        }
    }),
    // extract webpack runtime & manifest to avoid vendor chunk hash changing
    // on every build.
    new webpack.optimize.CommonsChunkPlugin({
        name: 'manifest'
    }),
    

    而 webpack4 则直接内置了 optimization 字段来实现这个功能,所以我们注释掉上面的代码,然后加入如下代码:

    // webpack.client.js
    optimization: {
        splitChunks: {
            chunks: 'all',
            cacheGroups: {
            styles: {
                name: 'styles',
                test: /css$/,
                enforce: true,
            },
            vendor: {
                name: 'vendor',
                test: /[/]node_modules[/]/,
                enforce: true,
            },
            },
        },
        runtimeChunk: {
            name: 'manifest',
        },
    },
    
    

    externals

    老项目是使用 externals 字段在服务端打包的时候防止 css 没有被引入,但是这里我们已经在服务端不打包 css 了,所以这个配置可以删去。但是这里我们加上如下配置,来防止引入 node_modules 里面的包,从而提高打包效率:

    // webpack.server.config.js
    externals: Object.keys(require('../package.json').dependencies),
    

    service-worker

    老项目是使用sw-precache-webpack-plugin来安装 service-worker 的,现在这个包已经被workbox-webpack-plugin代替了,相关文档在这里

    我们首先卸载 sw-precache-webpack-plugin 然后安装 workbox-webpack-plugin:

    // 卸载
    "sw-precache-webpack-plugin": "^0.11.4",
    
    // 安装
    "workbox-webpack-plugin": "^5.1.4"
    

    然后我们在webpack.client.config.js里面删掉 SWPrecachePlugin 的代码,加入 WorkboxPlugin 的相关配置:

    // webpack.client.config.js
    const WorkboxPlugin = require('workbox-webpack-plugin');
    
    if (process.env.NODE_ENV === 'production') {
      config.plugins.push(
        new WorkboxPlugin.GenerateSW({
          cacheId: 'vue-hn',
          swDest: 'service-worker.js',
          clientsClaim: true,
          skipWaiting: true,
          dontCacheBustURLsMatching: /./,
          exclude: [/.map$/, /.json$/],
          runtimeCaching: [
            {
              urlPattern: '/',
              handler: 'NetworkFirst'
            },
            {
              urlPattern: //(top|new|show|ask|jobs)/,
              handler: 'NetworkFirst'
            },
            {
              urlPattern: '/item/:id',
              handler: 'NetworkFirst'
            },
            {
              urlPattern: '/user/:id',
              handler: 'NetworkFirst'
            }
          ]
        })
      )
    }
    

    由于 service-worker 支持在 localhost 进行调试,所以我们更改一下老项目引入 service-worker 的代码:

    // entry-client.js
    if ('serviceWorker' in navigator && process.env.NODE_ENV === 'production') {
      window.addEventListener('load', () => {
        navigator.serviceWorker.register('/service-worker.js').then(registration => {
          console.log('SW registered: ', registration);
        }).catch(registrationError => {
          console.log('SW registration failed: ', registrationError);
        });
      });
    }
    

    虽然到这里就已经替换完成了,但是在实际打包之后,WorkboxPlugin 会生成一个带有hash的workbox.js文件,当我们更改 WorkboxPlugin 相关配置之后再打包,这个 hash 值会变化。这里面有一个问题就是,这个文件没有被 express 暴露出来,所以请求不到这个文件(express 只暴露了没带 hash 的 service-worker.js文件)。

    解决方法有2种,第一种是直接改entry-client.js里面的service-worker路径,在前面加上 dist。这样service-worker.js在请求 workbox.js 的时候回自己带上 dist 前缀。代码如下:

    // entry-client.js
    if ('serviceWorker' in navigator && process.env.NODE_ENV === 'production') {
      window.addEventListener('load', () => {
        navigator.serviceWorker.register('/dist/service-worker.js').then(registration => {
          console.log('SW registered: ', registration);
        }).catch(registrationError => {
          console.log('SW registration failed: ', registrationError);
        });
      });
    }
    

    另一种解决方法是在 express 里面动态引入带有hash的workbox.js文件。由于这个文件带有 hash 值,所以它不能被 express.static 直接引入,app.use 也不支持正则引入,所以我们需要获取 dist 文件夹下面的所有文件名,找出带有 workbox.js 的文件名,然后利用这个文件名通过 express.static 暴露出来,代码如下:

    // workbox dir
    const distFiles = fs.readdirSync('./dist')
    const workboxDir = distFiles.filter(name => /workbox-.*.js$/.test(name))
    
    if (workboxDir.length > 0) {
      app.use(`/${workboxDir[0]}`, serve(`./dist/${workboxDir[0]}`))
    }
    

    完工

    到这里就全部升级完毕了,详细代码可以参考我的vue-hackernews-2.0项目

    我学到了什么:

    1. 了解了一下 webpack 在 ssr 的各种配置
    2. 尝试了一些 node api
    3. 为以后编写cheer-fun的项目做准备
  • 相关阅读:
    新学期的合作
    软件工程问题及回答
    《程序猿的生命周期》阅读有感
    《构建之法》13~17章
    阅读《构建之法》十一、十二、十三章之感
    阅读《构建之法》十一、十二、十三章
    【.NET / C#】SubarrayUtils(查找子数组工具类)
    【Java】ComplexTimerTask (TimerTask 拓展封装)
    【Java】AesCbcCodec(AES_CBC加解密工具类)
    【Java】AesEcbCodec(AES_ECB加解密工具类)
  • 原文地址:https://www.cnblogs.com/yangzhou33/p/13800448.html
Copyright © 2020-2023  润新知