【问题标题】:webpack hot module replacement: css without refreshwebpack 热模块替换:css 不刷新
【发布时间】:2015-06-14 18:38:58
【问题描述】:

到目前为止,我一直在使用 livereload,这样每当我更改 JS 或模板时,页面都会刷新,而当我更改 CSS 时,它会在不刷新的情况下热交换新的 CSS。

我现在正在尝试 webpack,几乎得到了相同的行为,除了一个例外:当 CSS 更改时,它会刷新整个窗口。是否可以在不刷新的情况下使其热交换 CSS?

到目前为止的配置:

var webpackConfig = {
    entry: ["webpack/hot/dev-server", __dirname + '/app/scripts/app.js'],
    debug: true,
    output: {
        path: __dirname + '/app',
        filename: 'scripts/build.js'
    },
    devtool: 'source-map',
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new htmlWebpackPlugin({
            template: __dirname + '/app/index.html',
            inject: 'body',
            hash: true,
            config: config
        }),
        new webpack.ProvidePlugin({
            'angular': 'angular'
        }),
        new ExtractTextPlugin("styles.css")
    ],
    module: {
        loaders: [
            {
                test: /\.scss$/,
                loader: "style!css!sass?includePaths[]=" + __dirname + "/app/bower_components/compass-mixins/lib&includePaths[]=" + __dirname + '/instance/sth/styles&includePaths[]=' + __dirname + '/app/scripts'
            }
        ]
    }
};

【问题讨论】:

    标签: webpack webpack-dev-server


    【解决方案1】:

    这是使用ExtractTextPlugin 的缺点之一,如the project README 所述。您可以通过拆分配置来解决问题。 IE。在没有它的情况下有单独的开发配置和一个用于生产的配置。

    【讨论】:

    【解决方案2】:

    实际上有一个简单的方法可以做到这一点。我正在使用 sass-loader 和 extract-text-plugin 来生成 css 文件。

    你需要做的是添加 id 到你的 css 包含

      <link id="js-style" type="text/css" rel="stylesheet" href="/static/main.css">
    

    现在,您需要确保在发生 HMR 时使用当前版本/时间戳更新 url。你可以这样做:

    import '../style/main.scss'
    if (module.hot) {
      module.hot.accept('../style/main.scss', () => {
        const baseStyle = window.document.getElementById('js-style')
        baseStyle.setAttribute('href', '/static/main.css?v=' + new Date().valueOf)
      })
    }
    

    所以每当 css 发生变化时,我们都会修复 css include 的 url 以重新加载它。

    【讨论】:

      【解决方案3】:

      现在可以使用 angular2、带有热模块替换的 webpack、sass 源映射和外部加载的 css。我花了几天的时间玩它,但我成功了!

      依赖有style-loadercss-loadersass-loader(如果使用sass,如果没有,可以去掉sass loader)

      我在生产模式下使用 ExtractTextPlugin 来生成实际的 .css 文件。

      注意:为了让它工作,我不使用 stylesUrl 属性,而是在 @Component 装饰器之外导入 .scss 文件,以便样式在全局上下文中加载,而不是由组件限定。

      此配置允许使用 webpack 开发服务器将热模块替换为 SCSS 文件,并为生产模式提取文本插件以发出实际的 .css 文件。

      这是我的工作配置

      {
              test: /\.(scss)$/,
              use:
                isDevServer ? [
                    {
                      loader: 'style-loader',
                    },             
                    {
                      loader: 'css-loader',
                      options: { sourceMap: true }
                    },
                    {
                      loader: 'postcss-loader',
                      options: { postcss: [AutoPrefixer(autoPrefixerOptions)], sourceMap: true }
                    },
                    {
                      loader: 'sass-loader',
                      options: { sourceMap: true }
                    },
                    {
                      loader: 'sass-resources-loader',
                      options: {
                        resources: [
                          './src/assets/styles/variables.scss',
                          './src/assets/styles/mixins.scss']
                      }
                    }, 
                    /**
                     * The sass-vars-loader will convert the 'vars' property or any module.exports of 
                     * a .JS or .JSON file into valid SASS and append to the beginning of each 
                     * .scss file loaded.
                     *
                     * See: https://github.com/epegzz/sass-vars-loader
                     */
                    {
                      loader: '@epegzz/sass-vars-loader?',
                      options: querystring.stringify({
                        vars: JSON.stringify({
                          susyIsDevServer: susyIsDevServer
                        })
                      })
                    }] : // dev mode
                ExtractTextPlugin.extract({
                  fallback: "css-loader",
                  use: [
                    {
                      loader: 'css-loader',
                      options: { sourceMap: true }
                    },
                    {
                      loader: 'postcss-loader',
                      options: { postcss: [AutoPrefixer(autoPrefixerOptions)], sourceMap: true }
                    },
                    {
                      loader: 'sass-loader',
                      options: { sourceMap: true }
                    },
                    {
                      loader: 'sass-resources-loader',
                      options: {
                        resources: [
                          './src/assets/styles/variables.scss',
                          './src/assets/styles/mixins.scss']
                      }
                    }, {
                      loader: '@epegzz/sass-vars-loader?',
                      options: querystring.stringify({
                        vars: JSON.stringify({
                          susyIsDevServer: susyIsDevServer
                        })
                        // // Or use 'files" object to specify vars in an external .js or .json file
                        // files: [
                        //    path.resolve(helpers.paths.appRoot + '/assets/styles/sass-js-variables.js')
                        // ],
                      })
                    }],
                  publicPath: '/' // 'string' override the publicPath setting for this loader
                })
            },
      

      然后,在您的组件中,例如app.component.ts,您将需要您的app.style.scss 文件在@Component 装饰器的外部

      这就是诀窍。如果您使用stylesUrl 以“角度方式”加载样式,这将不起作用。这样做可以让你为延迟加载的组件延迟加载.css 样式表,从而使初始加载时间更快。

      app.component.css

      /*
       * THIS IS WHERE WE REQUIRE CSS/SCSS FILES THAT THIS COMPONENT NEEDS
       *
       * Function: To enable so-called "Lazy Loading" CSS/SCSS files "on demand" as the app views need them.
       * Do NOT add styles the "Angular2 Way" in the @Component decorator ("styles" and "styleUrls" properties)
       */
          import './app.style.scss'
      
      /**
       * AppComponent Component
       * Top Level Component
       */
      @Component({
         selector: 'body',
         encapsulation: ViewEncapsulation.None,
         host: { '[class.authenticated]': 'appState.state.isAuthenticated' },
         templateUrl: './app.template.html'
      })
      

      我在运行此设置时没有遇到任何问题。给你!

      2017 年 8 月更新:改进了 webpack 3+ 架构要求的配置,并适用于 Angular 4 AOT 编译。

      【讨论】:

      • 感谢您的广泛回答。我还需要尝试一下,这可能需要一段时间,因为我们将 webpack 项目搁置了一段时间,但你的答案看起来很有希望!
      【解决方案4】:

      虽然 ExtractTextPlugin 在其 README section 中声明“没有热模块替换”,我通过 BrowserSync API 手动更新 CSS 文件解决了这个问题

      我使用 gaze 监听我的 CSS 文件中的任何更改,然后使用 BrowserSync 更新它们。

          npm install gaze
      

      您也可以通过使用以下内容编辑构建脚本来轻松做到这一点:

        const { Gaze } = require('gaze');
      
        // Your own BrowserSync init
        browserSync.init({
          ...
        }, resolve);
      
        // Create a watcher:
        // You can watch/reload specific files according to your build/project structure
        const gaze = new Gaze('**/*.css');
        gaze.on('all', () => bs.reload('*.css'));
      

      希望对您有所帮助。

      【讨论】:

        【解决方案5】:

        您可以使用“css-hot-loader”为提取的 css 启用 HMR。 它非常适合我。

        【讨论】:

        • 您目前的回答更像是评论。要将其变成一个功能齐全的答案,如果您能多解释一下您建议的解决方案是如何工作的,它如何解决问题中提到的问题,并展示一个如何使用它的小例子,那就太好了。
        【解决方案6】:

        在使用 preactprefresh 的 webpack 5 中,我将 hot: true 更改为 hotOnly: true,并且样式在没有重新加载的情况下更改。

        【讨论】:

          猜你喜欢
          • 2018-09-22
          • 2019-02-15
          • 2017-06-28
          • 2017-06-20
          • 2017-02-27
          • 1970-01-01
          • 2017-07-06
          • 2018-01-17
          • 2018-05-30
          相关资源
          最近更新 更多