zhangyuang / ssr

A most advanced ssr framework support React17/React18/Vue2/Vue3 on Earth that implemented serverless-side render specification.
http://doc.ssr-fc.com/
MIT License
2.61k stars 284 forks source link

关于异步css模块增加preload以防止页面闪烁的问题 #78

Closed zcgzxg closed 3 years ago

zcgzxg commented 3 years ago

如题,是否在服务器渲染时,根据当前路由,对当前路由关联的异步加载的css文件增加preload? 我认为在webpack打包时,可以将关联关系记录下来,在服务器端渲染时根据引用关系增加css文件的preload.

zhangyuang commented 3 years ago

已经有了这个逻辑了啊

zhangyuang commented 3 years ago

1、你只能拿到页面的chunk name 不能拿到具体的异步模块,重复模块的 chunk 2、页面 的chunk preload 逻辑已经有了,异步模块重复模块的 chunk css preload 没有,也做不到。参考 http://doc.ssr-fc.com/docs/features$faq#%E4%BB%A3%E7%A0%81%E5%88%86%E5%89%B2%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98

zhangyuang commented 3 years ago

后续如果有更好的方案可以 reopen 本 issue

zcgzxg commented 3 years ago

通过给splitChunks的name属性传递一个函数,就可以记录到页面关联的异步css文件 代码如下:

const cssManifest = {}

/**
 * @see [config document](http://doc.ssr-fc.com/docs/api$config)
 * @type {import('ssr-types').IConfig}
 */
const config = {
  chainBaseConfig: (chain) => {
    chain.module
      .rule('compile')
      .use('babel-loader')
      .tap((args) => {
        args.plugins = args.plugins || []
        args.plugins.push([
          'import',
          {
            libraryName: 'ant-design-vue',
            libraryDirectory: 'lib', // 这里一定要用 lib
            style: true // true 代表 style/index.js 会加载 less 类型的文件
          },
          'ant-design-vue'
        ])
        return args
      })
  },
  chainClientConfig: chain => {
    chain.optimization
      .splitChunks({
        chunks: 'async',
        minSize: 20000,
        minChunks: 1,
        maxAsyncRequests: 30,
        maxInitialRequests: 30,
        enforceSizeThreshold: 50000,
        name(module, chunks, cacheGroupKey) {
          const moduleFileName = module
            .identifier()
            .split('/')
            .reduceRight((item) => item)
          const allChunksNames = chunks.map((item) => item.name)
          const name = `${cacheGroupKey}-${allChunksNames.join('~')}`

          if (
            moduleFileName.endsWith('.css') ||
            moduleFileName.endsWith('.less')
          ) {
            cssManifest[name + '.css'] = allChunksNames
          }
          return name
        },
        cacheGroups: {
          vendors: {
            test: /[\\/]node_modules[\\/]/,
            priority: -10,
            reuseExistingChunk: true
          },
          common: {
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true
          }
        }
      })
      .end()

    chain.plugin('WriteCssManifest').use(
      class WriteCssManifest {
        apply(compiler) {
          compiler.hooks.done.tapAsync(
            'WriteCssManifest',
            (params, callback) => {
              console.log(cssManifest)
              // 将cssManifest定入文件
              callback()
            }
          )
        }
      }
    )
  }
}

module.exports = config

输出结果:

{
  'vendors-error~not-found.css': [ 'error', 'not-found' ],
  'vendors-error.css': [ 'error' ],
  'vendors-not-found.css': [ 'not-found' ],
  'common-error~not-found.css': [ 'error', 'not-found' ],
  'default-error~not-found.css': [ 'error', 'not-found' ]
}

asset-manifest.json

{
  "vendors-error~not-found.css": "/client/static/css/vendors-error~not-found.3a4b319b.chunk.css",
  "vendors-error~not-found.js": "/client/static/js/vendors-error~not-found.f158e1c4.chunk.js",
  "Page.css": "/client/static/css/Page.9b4ee7a2.chunk.css",
  "Page.js": "/client/static/js/Page.09ca0ac9.chunk.js",
  "error.js": "/client/static/js/error.50cbdb75.chunk.js",
  "not-found.js": "/client/static/js/not-found.2b4040ec.chunk.js",
  "runtime~Page.js": "/client/static/js/runtime~Page.4e272446.js"
}

示例地址: git@code.aliyun.com:tn_zhuxg/vue3-ssr.git

zhangyuang commented 3 years ago

emmm试了下我没看出你要解决的问题是什么。你在什么情况下会出现闪烁呢。建议扫码加入微信群交流

zhangyuang commented 3 years ago

and 你的仓库并没有权限打开

zhangyuang commented 3 years ago

and 解决 antd 样式闪烁请参考http://doc.ssr-fc.com/docs/features$faq#%E5%B0%86%20css%20%E6%8F%90%E5%8F%96%E4%B8%BA%E4%B8%80%E4%B8%AA%E5%A4%A7%E6%96%87%E4%BB%B6 and 你不需要额外添加 babel-plugin-import 配置

zcgzxg commented 3 years ago

我不要将css提取成一个大文件,我想要将公共css分割出去,但是分割出去的css是异步加载的,会出现闪烁. 我想的解决办法是根据请求的页面找到对应的异步css,将它加到preload中

 <link rel="preload" href="page-a~page-b.common.css" as="style">
zhangyuang commented 3 years ago

如果是你分割的的css是多个页面重复的那肯定是异步的啊,自己用 extraCssOrder 手动引入。没看出你这种切割的必要性,切不切割都得加载完这个文件页面才是正常的。

zcgzxg commented 3 years ago

我觉得对于需要异步加载css的人来说,能够通过preload改善页面闪烁是有价值的。 对于复杂项目将所有初次渲染时用到的css打包成一个大文件也不合理。

zcgzxg commented 3 years ago

每个页面需要的css文件不一样,extraCssOrder并不能根据路由决定加载什么css