Webpack 4 没有按顺序加载页面

Posted

技术标签:

【中文标题】Webpack 4 没有按顺序加载页面【英文标题】:Webpack 4 doesn't load page in order 【发布时间】:2019-08-08 03:46:09 【问题描述】:

我已经升级到 webpack 4 for Rails。我将它与 Vue.js 2 一起使用。我还在我的配置中使用了块。但是自从升级以来,我注意到页面加载顺序很奇怪。页面在样式和 JS 加载之前加载 html,这不是之前发生的情况。我附上了之前和之后的视频链接,以便更好地理解问题。

我一直在到处寻找有同样问题的人,但我找不到......

With Webpack 3(before)

With Webpack 4(after)

这是我的配置文件:

开发配置

const environment = require('./environment')
const BundleAnalyzerPlugin =
  require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

environment.plugins.append(
  'BundleAnalyzerPlugin',
  new BundleAnalyzerPlugin()
)


module.exports = environment.toWebpackConfig()

环境(共享)配置

const  environment  = require('@rails/webpacker')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const vue = require('./loaders/vue')

const additionalConfig = 
  plugins: [
    new VueLoaderPlugin(),
  ],
  optimization: 
    splitChunks: 
      cacheGroups: 
        default: false,
        vendor: 
          name: 'vendor',
          chunks: 'all',
          test: /[\\/]node_modules[\\/]/,
          minChunks: 3,
        ,
      
    
  ,
  module: 
    rules: [
      test: /\.pug$/,
      loader: 'pug-plain-loader'
    , 
      test: /\.sass$/,
      use: ['vue-style-loader', 'css-loader', 'sass-loader']
    ]
  ,
  output: 
  ,
  devtool: 'source-map',


environment.config.merge(additionalConfig);

environment.loaders.prepend('vue', vue)

module.exports = environment

视频中页面相关的包

import 'element-ui/lib/theme-chalk/index.css';
import 'element-ui/lib/theme-chalk/display.css';
import 'flexboxgrid/css/flexboxgrid.css';

import Vue from 'vue/dist/vue.esm';
import VueCookies from 'vue-cookies';
import  DateTime  from 'luxon';

// ElementUI Components
import ElementUI from 'element-ui';
import locale from 'element-ui/lib/locale/lang/en';

// Custom Components
import TextSection from '../components/TextSection.vue';
import TopNavigation from '../components/navigation/TheTopNavigation.vue';

import  store  from '../store';

Vue.use(ElementUI,  locale );
Vue.use(VueCookies);

const app = new Vue(
  el: '#app',
  store,
  mounted() 
    var selector = document.querySelector("#app");
    var errors   = selector.dataset.errors;

    if (selector) 
      store.commit('base_states/authenticate',
        JSON.parse(selector.dataset.signedIn)
      );
    

    if (errors) 
      this.$message(
        dangerouslyUseHTMLString: true,
        message: JSON.parse(errors).join("\n"),
        type: 'error'
      );
    
  ,
  components:  TextSection, TopNavigation ,
);

if (!app.$cookies.get('timezone')) 
  app.$cookies.set("timezone", DateTime.local().zoneName);

该页面的 Rails 视图

#app data:  signed_in: "#user_signed_in?", errors: flash[:errors]  
  .landing-top
    .row.banner
      %top-navigation ":user" => user, "logo" => logo 
      .row.start-sm.around-sm.middle-sm.center-xs.landing-hero
        .col-lg-4.col-md-4.col-sm-4.col-xs-12
          %h1= t 'static.banner.headline'
          %p= t 'static.banner.subtitle'
          .actions
            %a.no-decoration class: "el-button el-button--success", href: "/events" 
              See upcoming events
        .col-lg-6.col-md-6.col-sm-6.col-xs-12
          = video_tag("https://s3.eu-west-2.amazonaws.com/vras-assets/product_preview_new.webm",
                      poster: preview_poster,
                      class: "preview-video", autoplay: "true",
                      muted: "true",          loop: "true" )
  .landing-body.site-padding
    .row.around-lg.middle-lg.middle-md.features
      .col-md-4.col-xs-12.feature-column
        = inline_svg 'icons/potion.svg', class: 'svg-icon'
        %text-section "title" => t('static.first_section.title_one'),
                       "text"  => t('static.first_section.text_one') 
      .col-md-4.col-xs-12.feature-column
        = inline_svg 'icons/map.svg', class: 'svg-icon'
        %text-section "title" => t('static.first_section.title_two'),
                       "text"  => t('static.first_section.text_two') 
      .col-md-4.col-xs-12.feature-column
        = inline_svg 'icons/unicorn.svg', class: 'svg-icon'
        %text-section "title" => t('static.first_section.title_third'),
                       "text"  => t('static.first_section.text_third') 
  .row.center-lg.center-xs.video-showcase
    .col-lg-10.col-md-10.col-xs-12
      = video_tag('https://s3.eu-west-2.amazonaws.com/vras-assets/preview.mp4',
                  poster: 'meta_cover.jpg',
                  class: 'preview-video',
                  autoplay: 'true',
                  muted: 'true',
                  loop: 'true')
    .col-lg-8.col-md-8.col-xs-10 style: "padding-top: 20px" 
      %h3
        = image_tag("bigscreen_logo.png", width: "250px")
        %br
        = t('static.third_section.title')
      %text-section "text"  => t('static.third_section.text') 
  .landing-body.site-padding
    .row.around-lg.middle-lg.middle-md style: "margin-bottom: 100px" 
      .col-lg-6.col-md-6.col-xs-12
        %text-section "title" => t('static.second_section.title'),
                       "text"  => t('static.second_section.text') 
      .col-lg-6.col-md-6.col-xs-12.first-xs.last-lg.last-md style: "text-align: center" 
        %iframe:title => "Discord Widget", :allowtransparency => "true", :frameborder => "0", :height => "519", :src => "https://discordapp.com/widget?id=402246704252059648&theme=dark", :width => "320"
  = render "footer"

= javascript_packs_with_chunks_tag 'landing_page'
= stylesheet_packs_with_chunks_tag 'landing_page'

更新

我的研究让我相信它是这个问题:

发生这种情况是因为您正在捆绑样式加载器,它将您的 CSS 作为字符串放入 Javascript 包中。

因此,当浏览器解析您的 JS 包(非常慢)时,HTML 将呈现(非常快)。在该捆绑包的末尾,浏览器将找到包含您的 CSS 字符串的模块。然后它会解析它并使用 Javascript 应用样式。

我找不到改进的方法,所以现在我已经将我需要的 CSS 提取到 Rails app/assets 文件夹中,以便在 webpack 和 Vue 之外加载。这在一定程度上解决了弹出问题,但我仍然觉得这是错误的解决方法,只是一种解决方法......

【问题讨论】:

【参考方案1】:

我建议确保样式表正常工作添加:

= content_for :head
  = stylesheet_packs_with_chunks_tag 'landing_page'

然后在应用布局(或主布局)中

= yield :head

这将确保样式表在 DOM 之前加载,并且在 javascript 生效时已准备就绪。

【讨论】:

不幸的是,这对问题没有帮助。无论我是否将样式表放在首位,它们似乎仍然无法按顺序加载。我什至会在最后说,据我所见【参考方案2】:

看起来你的 webpack3 配置在生成的 html 的顶部注入 css,而 webpack4 在底部注入。尝试将= stylesheet_packs_with_chunks_tag 'landing_page' 移到顶部。我不确定 landing_page 标签的 css 是什么。它可能不完整,其余的 css 是从 js 异步加载的。检查 webpack3 和 webpack4 生成的 html 代码,并检查生成的 css 块列表及其加载顺序。

【讨论】:

我认为它确实是异步加载的。我已经尝试将样式表放在更高的位置,但它根本没有做任何事情。作为一种解决方法,我将关键的 CSS 提取到 rails 样式表中,因此它可以在 webpack 和 Vue 之外加载。但是感觉还是不应该这样,如果我决定将所有 CSS 打包会发生什么? 查看此注释github.com/rails/webpacker/blob/master/docs/… 我确实看到了,并尝试将 extract_css 更改为 true,但并没有真正深入了解具体的事情。我再看一遍【参考方案3】:

虽然我还没有完全深入,但我找到了一个临时简单的解决方案,可以回到最初的 webpack 3 行为,即 JS/CSS 阻止页面加载,受 question 的启发

window.addEventListener('load', () => 
  ### Initialise Vue app
);

在加载我的 Vue.js 之前,它强制等待窗口加载所有 JS/CSS 资产。这适用于所有页面,但只有一个页面,因为除了登录页面之外的所有内容都仅由 Vue 组件构建。

对于登陆页面,我采用了@Berto 的建议,将 JS/CSS 包加载委托给头部,并获得了收益。所以现在我们也阻止了登陆页面上的执行。结合起来,我看到的加载行为与以前完全相同。

【讨论】:

以上是关于Webpack 4 没有按顺序加载页面的主要内容,如果未能解决你的问题,请参考以下文章

webpac入门

利用 React/Redux/React-Router 4/webpack 开发大型 web 项目时如何按需加载

使用 webpack 优化资源

webpack中loader为啥是从后往前加载的

按顺序执行 Webpack 打包程序

使用 HTMLWebpackPlugin 时如何通过 webpack 加载图片?