webpack4搭建的一次尝试

目前支持typescript,react,jsx,less,eslint,prettier,husky等javascript

具体的配置请查看:github.com/nvnvyezi/in…css

如需搭配electron,能够查看:github.com/nvnvyezi/el…html

好了,正文开始,这不是一个文章,只做为想本身搭建webpack的一个参考java

概念

Entry:指定webpack开始构建的入口模块,从该模块开始构建并计算出直接或间接依赖的模块或者库node

Output:告诉webpack如何命名输出的文件以及输出的目录react

Loaders:因为webpack只能处理javascript,因此咱们须要对一些非js文件处理成webpack可以处理的模块,好比sass文件webpack

PluginsLoaders将各种型的文件处理成webpack可以处理的模块,plugins有着很强的能力。插件的范围包括,从打包优化和压缩,一直到从新定义环境中的变量。但也是最复杂的一个。好比对js文件进行压缩优化的UglifyJsPlugin插件git

Chunk:coding split的产物,咱们能够对一些代码打包成一个单独的chunk,好比某些公共模块,去重,更好的利用缓存。或者按需加载某些功能模块,优化加载时间。在webpack3及之前咱们都利用CommonsChunkPlugin将一些公共代码分割成一个chunk,实现单独加载。在webpack4 中CommonsChunkPlugin被废弃,使用SplitChunksPlugines6

webpack启动参数

  • color 输出结果带彩色,好比:会用红色显示耗时较长的步骤
  • profile 输出性能数据,能够看到每一步的耗时
  • progress 输出当前编译的进度,以百分比的形式呈现
  • display-modules 默认状况下 node_modules 下的模块会被隐藏,加上这个参数能够显示这些被隐藏的模块
  • display-error-details 输出详细的错误信息

webpack4特性

  • Webpack4须要与webpack-cli一块儿使用
  • 新添了mode属性,
    • development
      • Process.env.NODE_ENV = development,需在启动时设置NODE_ENV=development,不然在编译过程当中取不到该值
      • 默认开启如下插件,利用持久化缓存
      • namedChunksPlugin:以名称固化chunk id,
      • namemodulesPlugin:以名称固化module id
    • production
      • Process.env.NODE_ENV = production,一样需配置
      • 默认开启如下插件
      • SideEffectsFlagPluginUglifyJsPlugin 用于 tree-shaking
      • FlagDependencyUsagePlugin :编译时标记依赖
      • FlagIncludedChunksPlugin :标记子chunks,防子chunks屡次加载
      • ModuleConcatenationPlugin :做用域提高(scope hosting),预编译功能,提高或者预编译全部模块到一个闭包中,提高代码在浏览器中的执行速度
      • NoEmitOnErrorsPlugin :在输出阶段时,遇到编译错误跳过
      • OccurrenceOrderPlugin :给常用的ids更短的值
      • SideEffectsFlagPlugin :识别 package.json 或者 module.rules 的 sideEffects 标志(纯的 ES2015 模块),安全地删除未用到的 export 导出
      • UglifyJsPlugin :删除未引用代码,并压缩
  • 移除 CommonsChunkPlugin插件,取而代之的是两个新的配置项(optimization.splitChunks 和 optimization.runtimeChunk)
  • module.loaders 替换为 modules.rules
  • webpack4 增长了 WebAssembly 的支持,能够直接 import/export wasm 模块,也能够经过编写 loaders 直接 import C++/C/Rust

splitChunks

能够参考https://segmentfault.com/a/1190000013476837github

extra-text-webpack-plugin

关于[hash][chunkhash]的区别,简单来讲,[hash]是编译(compilation)后的hash值,compilation对象表明某个版本的资源对应的编译进程。项目中任何一个文件改动,webpack就会从新建立compilation对象,而后计算新的compilation的hash值,全部的编译输出文件名都会使用相同的hash指纹,改一个就一块儿变。而[chunkhash]是根据具体模块文件的内容计算所得的hash值,某个文件的改动只会影响它自己的hash指纹,不会影响其余文件。

hash/chunkhash:

hash:在 webpack 一次构建中会产生一个 compilation 对象,该 hash 值是对 compilation 内全部的内容计算而来的

与整个项目的构建有关。只要整个项目中有文件更改,就会产生新的hash值,而且全部的文件共用一个hash值。

hash通常是结合CDN缓存来使用,经过webpack构建以后,生成对应文件名自动带上对应的MD5值。若是文件内容改变的话,那么对应文件哈希值也会改变,对应的HTML引用的URL地址也会改变,触发CDN服务器从源服务器上拉取对应数据,进而更新本地缓存。可是在实际使用的时候,这几种hash计算仍是有必定区别。

compiler对象表明的是配置完备的Webpack环境。 compiler对象只在Webpack启动时构建一次,由Webpack组合全部的配置项构建生成。

compilation对象表明某个版本的资源对应的编译进程。当使用Webpack的development中间件时,每次检测到项目文件有改动就会建立一个compilation,进而可以针对改动生产全新的编译文件。compilation对象包含当前模块资源、待编译文件、有改动的文件和监听依赖的全部信息。

compiler表明配置好的webpack环境,compilation针对随时可变得项目文件,只要文件有改动就会从新建立。

chunkhash:每个 chunk 都根据自身的内容计算而来。

根据不一样的entry进行文件依赖分析,构建对应的chunk,生成对应的hash值,便可以将一些公共库单独打包构建,只要不改动公共库的代码,生成的hash值就不变。

保证了在线上构建的时候只要文件内容没有更改就不会重复构建

contenthash:在js中引用css时,保证css不变的状况下hash值不变

juejin.im/post/5a4502…

分析webpack中的Compiler/Compilation/Stats对象及构建顺序:github.com/liangklfang…

tsconfig.json

概述

若是一个目录下存在一个tsconfig.json文件,那么它意味着这个目录是TypeScript项目的根目录。tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项。 一个项目能够经过如下方式之一来编译:

使用tsconfig.json

  • 不带任何输入文件的状况下调用tsc,编译器会从当前目录开始去查找tsconfig.json文件,逐级向上搜索父目录。
  • 不带任何输入文件的状况下调用tsc,且使用命令行参数--project(或-p)指定一个包含tsconfig.json文件的目录。

当命令行上指定了输入文件时,tsconfig.json文件会被忽略

配置示例

{
  "compilerOptions": {
    "module": "commonjs",
    "noImplicitAny": true,
    "removeComments": true,
    "preserveConstEnums": true,
    "sourceMap": true
  },
  "files": [
    "app.ts",
    "foo.ts",
  ],
  // 或者使用include,exclude指定待编译文件
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
  ]
}
复制代码

compilerOptions 用来配置编译选项,files 用来指定待编译文件。

这里的待编译文件是指入口文件,任何被入口文件依赖的文件

files 属性是一个数组,数组元素能够是相对文件路径和绝对文件路径。

includeexclude 属性也是一个数组,但数组元素是相似 glob 的文件模式。它支持的 glob 通配符包括:

  • * :匹配 0 或多个字符(注意:不含路径分隔符)
  • ? :匹配任意单个字符(注意:不含路径分隔符)
  • **/ :递归匹配任何子路径

TS 文件指拓展名为 .ts.tsx.d.ts 的文件。若是开启了 allowJs 选项,那 .js.jsx 文件也属于 TS 文件。

若是仅仅包含一个 * 或者 .* ,那么只有TS 文件才会被包含。

若是 filesinclude 都未设置,那么除了 exclude 排除的文件,编译器会默认包含路径下的全部 TS 文件

若是同时设置 filesinclude ,那么编译器会把二者指定的文件都引入。

若是未设置 exclude ,那其默认值为 node_modulesbower_componentsjspm_packages 和编译选项 outDir 指定的路径。

exclude 只对 include 有效,对 files 无效。即 files 指定的文件若是同时被 exclude 排除,那么该文件仍然会被编译器引入。

前面提到,任何被 filesinclude 引入的文件的依赖会被自动引入。 反过来,若是 B.tsA.ts 依赖,那么 B.ts 不能被 exclude 排除,除非 A.ts 也被排除了。

有一点要注意的是,编译器不会引入疑似为输出的文件。好比,若是引入的文件中包含 index.ts ,那么 index.d.tsindex.js 就会被排除。一般来讲,只有拓展名不同的文件命名法是不推荐的。

tsconfig.json 也能够为空文件,这种状况下会使用默认的编译选项来编译全部默认引入的文件。

官方编译选项列表:www.tslang.cn/docs/handbo…

能够参考:www.tslang.cn/docs/handbo…

tslint/eslint选择

ts.xcatliu.com/engineering…

Eslint规则:eslint.cn/docs/user-g…

参考掘金的eslint;juejin.im/post/5b3859…

react配置eslint一些规则: segmentfault.com/a/119000001…

eslint 配置项
  • root 限定配置文件的使用范围
  • parser 指定eslint的解析器
  • parserOptions 设置解析器选项
  • extends 指定eslint规范
  • plugins 引用第三方的插件
  • env 指定代码运行的宿主环境
  • rules 启用额外的规则或覆盖默认的规则
  • globals 声明在代码中的自定义全局变量

git提交检测/husky/pre-commit/lint-staged

husky继承了Git下全部的钩子,在触发钩子的时候,husky能够阻止不合法的commit,push等等。

husky是一个npm包,安装后,能够很方便的在package.json配置git hook 脚本 。

好比,在 package.json 内配置如

"scripts": {
    "lint": "eslint src"
  },
  "husky": {
    "hooks": {
      "pre-commit": "npm run lint"
    }
  },
复制代码

那么,在后续的每一次git commit 以前,都会执行一次对应的 hook 脚本npm run lint 。其余hook同理

pre-commit:github.com/PaicFE/blog…

lint-staged: github.com/okonet/lint…

prettire配置

prettier.io/docs/en/opt…

优化

  1. include & exclude
  2. babel-loader
  • cacheDirectory:默认值为 false。当有设置时,指定的目录将用来缓存 loader 的执行结果。以后的 webpack 构建,将会尝试读取缓存,来避免在每次执行时,可能产生的、高性能消耗的 Babel 从新编译过程(recompilation process)。若是设置了一个空值 (loader: 'babel-loader?cacheDirectory') 或者 true (loader: babel-loader?cacheDirectory=true),loader 将使用默认的缓存目录 node_modules/.cache/babel-loader,若是在任何根目录下都没有找到 node_modules 目录,将会降级回退到操做系统默认的临时文件目录。
  1. 引入babel runtime,避免重复引入
  2. resolve.modules解析时搜索的目录
  3. resolve.mainFields用于配置第三方模块使用那个入口文件

安装的第三方模块中都会有一个 package.json文件,用于描述这个模块的属性,其中有些字段用于描述入口文件在哪里,resolve.mainFields 用于配置采用哪一个字段做为入口文件的描述。

能够存在多个字段描述入口文件的缘由是由于有些模块能够同时用在多个环境中,针对不一样的运行环境须要使用不一样的代码。 以 isomorphic-fetch API 为例,它是 Promise的一个实现,但可同时用于浏览器和 Node.js 环境。

  1. resolve.alias配置项经过别名来把原导入路径映射成一个新的导入路径

  2. resolve.extensions在导入语句没带文件后缀时,webpack自动带上后缀去尝试查询文件是否存在

    1. 后缀列表尽量小
    2. 频率最高的往前方
    3. 导出语句里尽量带上后缀
  3. module.noParse让webpack忽略对部分没采用模块化的文件的递归解析处理

    1. 被忽略掉的文件里不该该包含 import 、 require 、 define 等模块化语句
  4. 使用动态连接库

    1. webapck.DllPlugin
      1. context (optional): manifest 文件中请求的上下文(context)(默认值为 webpack 的上下文(context))
      2. name: 暴露出的 DLL 的函数名 (TemplatePaths: [hash] & [name] )
      3. path: manifest json 文件的绝对路径 (输出文件)`
    2. webpack.DllReferencePlugin
      1. context: (绝对路径) manifest (或者是内容属性)中请求的上下文
      2. manifest: 包含 contentname 的对象,或者在编译时(compilation)的一个用于加载的 JSON manifest 绝对路径
      3. content (optional): 请求到模块 id 的映射 (默认值为 manifest.content)
      4. name (optional): dll 暴露的地方的名称 (默认值为 manifest.name) (可参考 externals)
      5. scope (optional): dll 中内容的前缀
      6. sourceType (optional): dll 是如何暴露的 (libraryTarget)
    3. libraryTargetlibrary
      1. output.libraryTarget 配置以何种方式导出库。
      2. output.library 配置导出库的名称。 它们一般搭配在一块儿使用。
    4. 推荐参考: segmentfault.com/a/119000001…
  5. HappyPack: 让Webpack把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。

    1. id: String 用惟一的标识符 id 来表明当前的 HappyPack 是用来处理一类特定的文件.

      loaders: Array 用法和 webpack Loader 配置中同样.

      threads: Number 表明开启几个子进程去处理这一类型的文件,默认是3个,类型必须是整数。

      verbose: Boolean 是否容许 HappyPack 输出日志,默认是 true。

      threadPool: HappyThreadPool 表明共享进程池,即多个 HappyPack 实例都使用同一个共享进程池中的子进程去处理任务,以防止资源占用过多。

      verboseWhenProfiling: Boolean 开启webpack --profile ,仍然但愿HappyPack产生输出。

      debug: Boolean 启用debug 用于故障排查。默认 false

  6. ParallelUglifyPlugin:能够把对JS文件的串行压缩变为开启多个子进程并行执行&oq=能够把对JS文件的串行压缩变为开启多个子进程并行执行

  7. 在支持es6的环境中直接使用es6,不进行转换

  8. splitChunks: 提取公共代码

  9. 区分环境,使用mode

  10. 代码分离

相关文章
相关标签/搜索