Webpack 的 sass-loader 构建时间较慢

2024-04-28

Summary

当我们改用 Webpack 处理 SASS 文件时,我们注意到在某些情况下构建时间变得非常慢。使用以下方法测量构建的不同部分的性能后测速插件 https://www.npmjs.com/package/speed-measure-webpack-plugin, 看起来sass 加载器 https://github.com/webpack-contrib/sass-loader罪魁祸首是……它很容易需要 10 秒才能构建(在我们进行一些修复之前需要 20 秒),这比我们想要的要长。

我很好奇人们是否有其他我没有介绍的优化构建 Sass 资产的策略。此时我已经经历了相当多的事情(其中一些经历了多次),但似乎仍然无法让构建时间足够短。就目标而言,目前大型重建(例如对许多文件中使用的组件进行更改)很容易需要 10-12 秒,如果可能的话,我希望将其缩短到接近 5 秒。

尝试过的解决方案

我们尝试了多种不同的解决方案,有些有效,有些则没有多大帮助。

  • 硬源插件 https://github.com/mzgoddard/hard-source-webpack-plugin- 这个效果相当好。根据该构建的缓存,它能够将构建时间缩短几秒钟。
  • 删除重复的导入(例如将相同的“variables.sass”文件导入到多个位置)-这也减少了几秒钟的构建时间
  • 将 SASS 和 SCSS 的组合更改为仅 SCSS - 我不确定为什么这会有所帮助,但它似乎确实缩短了我们的构建时间。也许因为所有内容都是相同的文件类型,所以编译起来更容易? (这里可能发生了其他事情来混淆结果,但它似乎确实始终有帮助)。
  • 将 sass-loader 替换为快速 sass 加载器 https://github.com/yibn2008/fast-sass-loader- 很多人推荐这个,但是当我让它工作时,它似乎根本没有改变构建时间。我不确定为什么......也许存在配置问题。
  • 利用缓存加载器 https://github.com/webpack-contrib/cache-loader——这似乎也没有任何改善。
  • 禁用 Sass 的源映射 - 这似乎产生了很大的影响,将构建时间减少了一半(从应用更改时开始)
  • 尝试使用includePaths对于从node_modules加载的SASS - 这是在a上建议的git问题 https://github.com/webpack-contrib/sass-loader/issues/296我发现 sass-loader 遇到了他们所谓的“自定义导入器”的问题。我的理解是,通过使用 includePaths,SASS 能够依赖那些提供的绝对路径,而不是使用低效的算法来解析像 node_modules 这样的地方的路径

从一些简短的统计数据来看,我们似乎有大约 16k 行 SASS 代码分布在 150 个 SASS 文件中。有些具有相当数量的代码,而另一些则较少,这些文件的 LOC 的简单平均值约为 107 LOC/文件。

以下是正在使用的配置。该应用程序是一个 Rails 应用程序,大部分 Webpack 配置都是通过 Webpacker gem 处理的。

{
  "mode": "production",
  "output": {
    "filename": "js/[name].js",
    "chunkFilename": "js/[name].js",
    "hotUpdateChunkFilename": "js/[id]-[hash].hot-update.js",
    "path": "myApp/public/packs",
    "publicPath": "/packs/"
  },
  "resolve": {
    "extensions": [".mjs", ".js", ".sass", ".scss", ".css", ".module.sass", ".module.scss", ".module.css", ".png", ".svg", ".gif", ".jpeg", ".jpg"],
    "plugins": [{
      "topLevelLoader": {}
    }],
    "modules": ["myApp/app/assets/javascript", "myApp/app/assets/css", "node_modules"]
  },
  "resolveLoader": {
    "modules": ["node_modules"],
    "plugins": [{}]
  },
  "node": {
    "dgram": "empty",
    "fs": "empty",
    "net": "empty",
    "tls": "empty",
    "child_process": "empty"
  },
  "devtool": "source-map",
  "stats": "normal",
  "bail": true,
  "optimization": {
    "minimizer": [{
      "options": {
        "test": {},
        "extractComments": false,
        "sourceMap": true,
        "cache": true,
        "parallel": true,
        "terserOptions": {
          "output": {
            "ecma": 5,
            "comments": false,
            "ascii_only": true
          },
          "parse": {
            "ecma": 8
          },
          "compress": {
            "ecma": 5,
            "warnings": false,
            "comparisons": false
          },
          "mangle": {
            "safari10": true
          }
        }
      }
    }],
    "splitChunks": {
      "chunks": "all",
      "name": false
    },
    "runtimeChunk": true
  },
  "externals": {
    "moment": "moment"
  },
  "entry": {
    "entry1": "myApp/app/assets/javascript/packs/entry1.js",
    "entry2": "myApp/app/assets/javascript/packs/entry2.js",
    "entry3": "myApp/app/assets/javascript/packs/entry3.js",
    "entry4": "myApp/app/assets/javascript/packs/entry4.js",
    "entry5": "myApp/app/assets/javascript/packs/entry5.js",
    "entry6": "myApp/app/assets/javascript/packs/entry6.js",
    "entry7": "myApp/app/assets/javascript/packs/entry7.js",
    "entry8": "myApp/app/assets/javascript/packs/entry8.js",
    "landing": "myApp/app/assets/javascript/packs/landing.js",
    "entry9": "myApp/app/assets/javascript/packs/entry9.js",
    "entry10": "myApp/app/assets/javascript/packs/entry10.js",
    "entry11": "myApp/app/assets/javascript/packs/entry11.js",
    "entry12": "myApp/app/assets/javascript/packs/entry12.js",
    "entry13": "myApp/app/assets/javascript/packs/entry13.js",
    "entry14": "myApp/app/assets/javascript/packs/entry14.js",
    "entry15": "myApp/app/assets/javascript/packs/entry15.js"
  },
  "module": {
    "strictExportPresence": true,
    "rules": [{
      "parser": {
        "requireEnsure": false
      }
    }, {
      "test": {},
      "use": [{
        "loader": "file-loader",
        "options": {
          "context": "app/assets/javascript"
        }
      }]
    }, {
      "test": {},
      "use": ["myApp/node_modules/mini-css-extract-plugin/dist/loader.js", {
        "loader": "css-loader",
        "options": {
          "sourceMap": true,
          "importLoaders": 2,
          "localIdentName": "[name]__[local]___[hash:base64:5]",
          "modules": false
        }
      }, {
        "loader": "postcss-loader",
        "options": {
          "config": {
            "path": "myApp"
          },
          "sourceMap": true
        }
      }],
      "sideEffects": true,
      "exclude": {}
    }, {
      "test": {},
      "use": ["myApp/node_modules/mini-css-extract-plugin/dist/loader.js", {
        "loader": "css-loader",
        "options": {
          "sourceMap": true,
          "importLoaders": 2,
          "localIdentName": "[name]__[local]___[hash:base64:5]",
          "modules": false
        }
      }, {
        "loader": "postcss-loader",
        "options": {
          "config": {
            "path": "myApp"
          },
          "sourceMap": false,
          "plugins": [null, null]
        }
      }, {
        "loader": "sass-loader",
        "options": {
          "sourceMap": false,
          "sourceComments": true
        }
      }],
      "sideEffects": true,
      "exclude": {}
    }, {
      "test": {},
      "use": ["myApp/node_modules/mini-css-extract-plugin/dist/loader.js", {
        "loader": "css-loader",
        "options": {
          "sourceMap": true,
          "importLoaders": 2,
          "localIdentName": "[name]__[local]___[hash:base64:5]",
          "modules": true
        }
      }, {
        "loader": "postcss-loader",
        "options": {
          "config": {
            "path": "myApp"
          },
          "sourceMap": true
        }
      }],
      "sideEffects": false,
      "include": {}
    }, {
      "test": {},
      "use": ["myApp/node_modules/mini-css-extract-plugin/dist/loader.js", {
        "loader": "css-loader",
        "options": {
          "sourceMap": true,
          "importLoaders": 2,
          "localIdentName": "[name]__[local]___[hash:base64:5]",
          "modules": true
        }
      }, {
        "loader": "postcss-loader",
        "options": {
          "config": {
            "path": "myApp"
          },
          "sourceMap": true
        }
      }, {
        "loader": "sass-loader",
        "options": {
          "sourceMap": true
        }
      }],
      "sideEffects": false,
      "include": {}
    }, {
      "test": {},
      "include": {},
      "exclude": {},
      "use": [{
        "loader": "babel-loader",
        "options": {
          "babelrc": false,
          "presets": [
            ["@babel/preset-env", {
              "modules": false
            }]
          ],
          "cacheDirectory": "tmp/cache/webpacker/babel-loader-node-modules",
          "cacheCompression": true,
          "compact": false,
          "sourceMaps": false
        }
      }]
    }, {
      "test": {},
      "include": ["myApp/app/assets/javascript", "myApp/app/assets/css"],
      "exclude": {},
      "use": [{
        "loader": "babel-loader",
        "options": {
          "cacheDirectory": "tmp/cache/webpacker/babel-loader-node-modules",
          "cacheCompression": true,
          "compact": true
        }
      }]
    }, {
      "test": "myApp/node_modules/jquery/dist/jquery.js",
      "use": [{
        "loader": "expose-loader",
        "options": "jQuery"
      }, {
        "loader": "expose-loader",
        "options": "$"
      }]
    }, {
      "test": "myApp/node_modules/popper.js/dist/umd/popper.js",
      "use": [{
        "loader": "expose-loader",
        "options": "Popper"
      }]
    }, {
      "test": "myApp/node_modules/scroll-depth/jquery.scrolldepth.js",
      "use": [{
        "loader": "expose-loader",
        "options": "scrollDepth"
      }]
    }]
  },
  "plugins": [{
    "environment_variables_plugin": "values don't really matter in this case I think"
  }, {
    "options": {},
    "pathCache": {},
    "fsOperations": 0,
    "primed": false
  }, {
    "options": {
      "filename": "css/[name]-[contenthash:8].css",
      "chunkFilename": "css/[name]-[contenthash:8].chunk.css"
    }
  }, {}, {
    "options": {
      "test": {},
      "cache": true,
      "compressionOptions": {
        "level": 9
      },
      "filename": "[path].gz[query]",
      "threshold": 0,
      "minRatio": 0.8,
      "deleteOriginalAssets": false
    }
  }, {
    "pluginDescriptor": {
      "name": "OptimizeCssAssetsWebpackPlugin"
    },
    "options": {
      "assetProcessors": [{
        "phase": "compilation.optimize-chunk-assets",
        "regExp": {}
      }],
      "assetNameRegExp": {},
      "cssProcessorOptions": {},
      "cssProcessorPluginOptions": {}
    },
    "phaseAssetProcessors": {
      "compilation.optimize-chunk-assets": [{
        "phase": "compilation.optimize-chunk-assets",
        "regExp": {}
      }],
      "compilation.optimize-assets": [],
      "emit": []
    },
    "deleteAssetsMap": {}
  }, {
    "definitions": {
      "$": "jquery",
      "jQuery": "jquery",
      "jquery": "jquery",
      "window.$": "jquery",
      "window.jQuery": "jquery",
      "window.jquery": "jquery",
      "Popper": ["popper.js", "default"]
    }
  }, {
    "definitions": {
      "process.env": {
        "MY_DEFINED_ENV_VARS": "my defined env var values"
      }
    }
  }, {
    "options": {}
  }]
}

我认为有几个问题:

1:可能是因为您没有指定要测试的文件(因此 webpack 可能会搜索所有内容):

...
"test": {},
  "use": ["myApp/node_modules/mini-css-extract-plugin/dist/loader.js", {
   "loader": "css-loader"
}
...

尝试更换test: {} with test: /\.(sa|sc|c)ss$/ or test: /\.module.(sa|sc|c)ss$/如果使用 css 模块

1b:尝试修改test也可以键入其他加载程序,例如babel 通常只需要查找 js/ts(x) 文件,因此如果是这种情况请指定。

1c:也尝试使用包含/排除属性

2:该配置中有 4 个 css-loader 实例 - 除非您是服务器端渲染,否则您只需要两个(一个用于 sc/sa/css 模块,一个用于普通 sa/sc/ss)

这是一个示例 css 加载器配置,我希望它对您有所帮助(提示:每个项目加载 css 的方式通常有所不同,因此请务必检查 webpack/css-loader 文档中的模块选项)

{
  test: /\.(sa|sc|c)ss$/,
  use: [
    {
      loader: MiniCssExtractPlugin.loader,
      options: {
        esModule: true,
        modules: {
          namedExport: true,
        },
      },
    },
    {
      loader: 'css-loader',
      options: {
        sourceMap: !isProd,
        importLoaders: 2,
        esModule: true,
        modules: {
          auto: true,
          namedExport: true,
        },
      },
    },
    {
      loader: 'postcss-loader',
      options: {
        sourceMap: !isProd,
      },
    },
    {
      loader: 'sass-loader',
      options: {
        sourceMap: !isProd,
      },
    },
  ]
}

陷阱:webpack 加载器是反向处理的,因此对于此示例配置,处理顺序是 sass -> postcss -> css -> minicss

不幸的是,对于 webpack 的 css 问题很少有直接/直接的答案,需要深入研究文档并找出您的项目需要哪些选项。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Webpack 的 sass-loader 构建时间较慢 的相关文章

  • 有没有什么好的工具可以查看和浏览ant构建文件?

    我发现很难读取 ant 构建文件 特别是如果构建文件包含大量导入文件 例如属性文件和其他 xml 构建文件 因此 我想知道是否有一些好的工具可以提供帮助 例如在 IDE 中查看和浏览源代码 提前致谢 Try 盛大 这里 http www g
  • Renderscript 示例构建错误

    所以我想尝试使用 RenderScript 的示例 并在 Eclipse 中导入了 HelloWorld 但它给了我这样的错误 2011 10 25 13 10 48 HelloWorld home mileoresko workspace
  • 无法使用 build auto 和 tfs 13 修改 .csproj 文件

    我创建了一个名为的工作流活动EditCsproj这是我添加到构建模板中的 C 类 我把它放在后面Initialize Workspace step 此工作流程必须获取所有 csproj我作为参数提供的目录路径中的文件 并且必须修改它们 但对
  • 节点 sass 无效 CSS

    node sass 是否支持 use 由于我收到此错误 SassError t family fonts 之后的 CSS 无效 预期的表达式 例如 1px 粗体 为 roboto 这是 Nav scss 的代码 nav width 100
  • scss bootstrap 4 覆盖地图

    我正在尝试使用 Bootstrap 4 进行 scss 但我不知道如何正确地覆盖变量 使用映射 自定义 scss Your variable overrides primary rgb 40 167 36 spacer 1 spacers
  • 无法在 typeScript 和 Webpack 中使用 p5.js

    我有一个使用图书馆的项目p5 js https github com processing p5 js Details 我的 Webpack 配置是 const path require path module exports entry
  • 离子服务后找不到模块(webpack)/hot/emitter @angular-devkit/build-Angular - Ionic 4

    Stack 节点 v10 15 1 离子4 10 1 当我跑步时ionic serve I get webpack hot emitter js ng 中的错误找不到模块 错误 无法 解决 事件 zazou node modules ang
  • 在许多驱动程序文件夹中创建 build-in.o

    我正在用我的自定义驱动程序构建内核 成功构建后 我发现了许多 build in o 文件 任何人都可以详细说明这些文件是如何在这里结束的吗 我只能怀疑这些与更高级别的 makefile 有关 built in o 文件是未构建为模块的内核的
  • 即使 WebPack 构建工作正常,VS Code 显示未找到模块

    我的 VS Code 说它找不到导入 即使我的 WebPack 构建仍然有效 这是进口 import as tf from tensorflow tfjs 以及来自 VS Code 的消息 找不到模块 tensorflow tfjs 您的意
  • 从字符串变量导入模块

    我需要从内存变量导入 JavaScript 模块 我知道这可以使用SystemJS and Webpack 但我找不到一个好的工作示例或文档 文档主要讨论 js 文件的动态导入 基本上我需要像下面这样导入模块 let moduleData
  • 如何在 Xcode 中自动增加内部版本号 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我在这个网站上找到了很多解决方案和脚本 但在 Xcode 中增加构建号的最简单的解决方案是 转到 TARGETS 部分中的 Build P
  • 如何使用 go1.6.2 构建 linux 32 位

    有没有任何组合GOARCH and GOOS我可以设置哪些值来构建 ELF 32 位二进制文 件 GOOS linux and GOARCH 386 更多示例 架构 32 bit gt GOARCH 386 64 bit gt GOARCH
  • 如何让 webpack 和 iis express 协同工作?

    I have Angular 2 和 Webpack 2 入门 https github com qdouble angular webpack2 starter它通过 webpack dev server 在节点上运行 我如何使用 web
  • 如何减少 WEBPACK + VUEJS 中的包大小

    我遵循了很多有关如何减小捆绑包大小的教程 但没有任何内容对捆绑包大小产生任何影响 我不知道为什么 每次当我向 webpack 添加一些新代码时 我的包大小都保持与以前相同 我的应用程序是使用 vue cli 3 pwa 插件 webpack
  • 如何生成源文件并用gradle编译

    我有一个类似于以下内容的 gradle 构建脚本 apply plugin war task genSources lt lt here I generate some java files making sure that source
  • 如何让 webpack 转换 React 生产文件?

    当我使用 webpack 与 React 16 捆绑我的应用程序时 我在浏览器中收到 Uncaught ReferenceError require is not Defined 对于react和react dom 导致错误的资源是reac
  • 使用 Webpack 代理创建 React 应用程序中的 WebSockets

    我使用版本 3 1 2 2019 年 9 月 19 日 中的 Create React App 创建了我的 React 应用程序 我试图为 Web Socket 请求配置代理 但似乎当我使用代理时 未建立连接 我用过THIS https g
  • 通过命令行参数更改默认的 ant 目标

    最近我被分配了一个任务 让ant能够为不同的环境构建war包 除了一项功能外 我几乎完成了 蚂蚁接受一个env参数类似 Denv DEV 并使用不同的配置文件来制作war包 但默认目标是start它将构建 部署并启动 tomcat 我不希望
  • 未找到 Gradle DSL 方法:“versionCode()”

    构建我的 Android 项目时遇到问题 我使用Grgit https github com ajoberstar grgit填写versionCode and versionName在 gradle 中 一切工作正常 直到我将 Andro
  • 将 ESLint 与 Airbnb 样式和选项卡结合使用 (React.js)

    我正在开发一个 React js 应用程序 并且正在尝试检查我的代码 我将 ESLint 与 Airbnb 风格一起使用 但出现以下错误 src Test jsx 4 2 error Unexpected tab character no

随机推荐