>  기사  >  웹 프론트엔드  >  파일 검색 범위를 좁히기 위한 Webpack 최적화 구성의 자세한 예

파일 검색 범위를 좁히기 위한 Webpack 최적화 구성의 자세한 예

小云云
小云云원래의
2017-12-25 16:37:121357검색

Webpack이 시작된 후 구성된 항목에서 시작하여 파일의 가져오기 문을 구문 분석한 다음 재귀적으로 구문 분석합니다. 이번 글은 Webpack 최적화 관련 지식을 중심으로 파일 검색 범위를 좁혀가며 최적화 방법을 좀 더 자세히 소개하고 있으니, 필요한 친구들이 참고하면 좋을 것 같습니다.

import 문이 나타나면 Webpack은 두 가지 작업을 수행합니다.

1 import 문에 따라 가져올 해당 파일을 찾습니다. 예를 들어 require('react') import 문에 해당하는 파일은 ./node_modules/react/react.js이고, require('./util')에 해당하는 파일은 ./util.js입니다.

2. 가져올 파일의 검색된 접미사에 따라 구성의 로더를 사용하여 파일을 처리합니다. 예를 들어 ES6를 사용하여 개발된 JavaScript 파일은 babel-loader를 사용하여 처리해야 합니다.

위 두 가지는 파일 처리 속도가 매우 빠르지만, 프로젝트가 커지면 파일 개수도 매우 많아지고, 빌드 속도가 느려지는 문제가 노출됩니다.

위의 두 가지는 피할 수 없지만 속도를 높이려면 최소화해야 합니다.

다음에서는 이를 최적화하는 방법을 하나씩 소개하겠습니다.

로더 구성 최적화

로더에 의한 파일 변환 작업은 시간이 많이 걸리므로 로더에서 처리할 수 있는 파일을 가능한 한 적게 허용해야 합니다.

2-3 모듈에서는 로더를 사용할 때 테스트, 포함, 제외 세 가지 구성 항목을 사용하여 로더가 규칙을 적용하려는 파일을 적중할 수 있다고 소개했습니다.

Loader에서 처리할 수 있는 파일을 가능한 한 적게 허용하려면 포함을 사용하여 처리해야 하는 파일만 대상으로 삼을 수 있습니다.

ES6를 사용하는 프로젝트를 예로 들면 babel-loader를 구성할 때 다음과 같이 할 수 있습니다.

module.exports = {
 module: {
  rules: [
   {
    // 如果项目源码中只有 js 文件就不要写成 /\.jsx?$/,提升正则表达式性能
    test: /\.js$/,
    // babel-loader 支持缓存转换出的结果,通过 cacheDirectory 选项开启
    use: ['babel-loader?cacheDirectory'],
    // 只对项目根目录下的 src 目录中的文件采用 babel-loader
    include: path.resolve(__dirname, 'src'),
   },
  ]
 },
};

Loader를 구성할 때 포함을 통해 적중 범위를 좁힐 수 있도록 프로젝트의 디렉터리 구조를 적절하게 조정할 수 있습니다.

Resolve.modules 구성 최적화

2-4 Resolve에서 소개된 Resolve.modules는 Webpack이 타사 모듈을 검색하는 디렉터리를 구성하는 데 사용됩니다.

Resolve.modules의 기본값은 ['node_modules']입니다. 이는 먼저 현재 디렉터리의 ./node_modules 디렉터리로 이동하여 찾고 있는 모듈을 찾을 수 없으면 상위 수준으로 이동한다는 의미입니다. ../node_modules 디렉토리에서 찾으세요. 그렇지 않다면 ../../node_modules 등에서 검색하세요. 이는 Node.js의 모듈 검색 메커니즘과 매우 유사합니다.

설치된 타사 모듈이 모두 프로젝트 루트 디렉터리의 ./node_modules 디렉터리에 배치되면 기본 방식으로 레이어별로 검색할 필요가 없습니다. 타사 모듈을 저장하기 위한 절대 경로를 지정할 수 있습니다. 검색을 줄이기 위한 구성은 다음과 같습니다.

module.exports = {
 resolve: {
  // 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
  // 其中 __dirname 表示当前工作目录,也就是项目根目录
  modules: [path.resolve(__dirname, 'node_modules')]
 },
};

resolve.mainFields 구성 최적화

2-4 Resolve에서 소개된,solve.mainFields는 타사 모듈이 사용하는 항목 파일을 구성하는 데 사용됩니다.

모든 설치된 타사 모듈에는 이 모듈의 속성을 설명하는 데 사용되는 package.json 파일이 있습니다. 일부 필드는 항목 파일의 위치를 ​​설명하는 데 사용됩니다. 설명으로 사용되는 필드를 구성하는 데 사용됩니다. 항목 파일의

항목 파일을 설명하는 필드가 여러 개 있을 수 있는 이유는 일부 모듈이 동시에 여러 환경에서 사용될 수 있고, 운영 환경에 따라 다른 코드를 사용해야 하기 때문입니다.

isomorphic-fetch를 예로 들면 fetch API의 구현이지만 브라우저와 Node.js 환경 모두에서 사용할 수 있습니다.

package.json에는 2개의 항목 파일 설명 필드가 있습니다.

{
 "browser": "fetch-npm-browserify.js",
 "main": "fetch-npm-node.js"
}

isomorphic-fetch는 fetch API의 구현 메커니즘이 다르기 때문에 브라우저에서 기본 fetch 또는 XMLHttpRequest 구현을 통해 서로 다른 실행 환경에서 서로 다른 코드를 사용합니다. , http 모듈을 통해 Node.js에서 구현됩니다.

resolve.mainFields의 기본값은 현재 대상 구성과 관련됩니다. 해당 관계는 다음과 같습니다.

  • 대상이 웹 또는 webworker인 경우 값은 ["browser", "module", "main"입니다. "]

  • target이 다른 상황인 경우 값은 ["module", "main"]

web과 동일한 대상을 예로 들면 Webpack은 먼저 타사의 브라우저 필드를 사용합니다. 모듈의 항목 파일을 찾으려면 모듈이 없으면 모듈 필드가 사용됩니다.

검색 단계를 줄이기 위해 타사 모듈의 항목 파일 설명 필드를 지정할 때 이를 최소한으로 설정할 수 있습니다.

대부분의 타사 모듈은 기본 필드를 사용하여 항목 파일의 위치를 ​​설명하므로 Webpack은 다음과 같이 구성할 수 있습니다.

module.exports = {
 resolve: {
  // 只采用 main 字段作为入口文件描述字段,以减少搜索步骤
  mainFields: ['main'],
 },
};

이 방법을 사용하여 최적화하는 경우 모든 타사 모듈의 항목 파일 설명 필드를 고려해야 합니다. -런타임이 의존하는 파티 모듈. 모듈 하나가 잘못되더라도 빌드된 코드가 제대로 실행되지 않을 수 있습니다.

Resolve.alias 구성 최적화

2-4 Resolve에서 도입된 Resolve.alias 구성 항목은 별칭을 통해 원래 가져오기 경로를 새 가져오기 경로에 매핑합니다.

실제 프로젝트에서 우리는 종종 거대한 타사 모듈에 의존합니다. React 라이브러리를 예로 들면 node_modules 디렉터리에 설치된 React 라이브러리의 디렉터리 구조는 다음과 같습니다.

├── dist
│   ├── react.js
│   └── react.min.js
├── lib
│   ... 还有几十个文件被忽略
│   ├── LinkedStateMixin.js
│   ├── createClass.js
│   └── React.js
├── package.json
└── react.js

可以看到发布出去的 React 库中包含两套代码:

  • 一套是采用 CommonJS 规范的模块化代码,这些文件都放在 lib 目录下,以 package.json 中指定的入口文件 react.js 为模块的入口。

  • 一套是把 React 所有相关的代码打包好的完整代码放到一个单独的文件中,这些代码没有采用模块化可以直接执行。其中 dist/react.js 是用于开发环境,里面包含检查和警告的代码。 dist/react.min.js 是用于线上环境,被最小化了。

默认情况下 Webpack 会从入口文件 ./node_modules/react/react.js 开始递归的解析和处理依赖的几十个文件,这会时一个耗时的操作。

通过配置 resolve.alias 可以让 Webpack 在处理 React 库时,直接使用单独完整的 react.min.js 文件,从而跳过耗时的递归解析操作。

相关 Webpack 配置如下:

module.exports = {
 resolve: {
  // 使用 alias 把导入 react 的语句换成直接使用单独完整的 react.min.js 文件,
  // 减少耗时的递归解析操作
  alias: {
   'react': path.resolve(__dirname, './node_modules/react/dist/react.min.js'),
  }
 },
};

除了 React 库外,大多数库发布到 Npm 仓库中时都会包含打包好的完整文件,对于这些库你也可以对它们配置 alias。
但是对于有些库使用本优化方法后会影响到后面要讲的 使用 Tree-Shaking 去除无效代码 的优化,因为打包好的完整文件中有部分代码你的项目可能永远用不上。

一般对整体性比较强的库采用本方法优化,因为完整文件中的代码是一个整体,每一行都是不可或缺的。

但是对于一些工具类的库,例如 lodash ,你的项目可能只用到了其中几个工具函数,你就不能使用本方法去优化,因为这会导致你的输出代码中包含很多永远不会执行的代码。

优化 resolve.extensions 配置

在导入语句没带文件后缀时,Webpack 会自动带上后缀后去尝试询问文件是否存在。

在 2-4 Resolve 中介绍过 resolve.extensions 用于配置在尝试过程中用到的后缀列表,默认是:

extensions: ['.js', '.json']

也就是说当遇到 require('./data') 这样的导入语句时,Webpack 会先去寻找 ./data.js 文件,如果该文件不存在就去寻找 ./data.json 文件,如果还是找不到就报错。

如果这个列表越长,或者正确的后缀在越后面,就会造成尝试的次数越多,所以 resolve.extensions 的配置也会影响到构建的性能。

在配置 resolve.extensions 时你需要遵守以下几点,以做到尽可能的优化构建性能:

  • 后缀尝试列表要尽可能的小,不要把项目中不可能存在的情况写到后缀尝试列表中。

  • 频率出现最高的文件后缀要优先放在最前面,以做到尽快的退出寻找过程。

  • 在源码中写导入语句时,要尽可能的带上后缀,从而可以避免寻找过程。例如在你确定的情况下把 require('./data') 写成 require('./data.json') 。

相关 Webpack 配置如下:

module.exports = {
 resolve: {
  // 尽可能的减少后缀尝试的可能性
  extensions: ['js'],
 },
};

优化 module.noParse 配置

在 2-3 Module 中介绍过 module.noParse 配置项可以让 Webpack 忽略对部分没采用模块化的文件的递归解析处理,这样做的好处是能提高构建性能。

原因是一些库,例如 jQuery 、ChartJS, 它们庞大又没有采用模块化标准,让 Webpack 去解析这些文件耗时又没有意义。

在上面的 优化 resolve.alias 配置 中讲到单独完整的 react.min.js 文件就没有采用模块化,让我们来通过配置 module.noParse 忽略对 react.min.js 文件的递归解析处理,

相关 Webpack 配置如下:

const path = require('path');
module.exports = {
 module: {
  // 独完整的 `react.min.js` 文件就没有采用模块化,忽略对 `react.min.js` 文件的递归解析处理
  noParse: [/react\.min\.js$/],
 },
};

注意被忽略掉的文件里不应该包含 import 、 require 、 define 等模块化语句,不然会导致构建出的代码中包含无法在浏览器环境下执行的模块化语句。

相关推荐:

Webpack实战之构建 Electron 应用实例详解

详解Webpack框架核心概念

webpack学习教程之前端性能优化总结

위 내용은 파일 검색 범위를 좁히기 위한 Webpack 최적화 구성의 자세한 예의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.