Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

webpack 学习整理 #2

Open
16slowly opened this issue Jul 16, 2018 · 3 comments
Open

webpack 学习整理 #2

16slowly opened this issue Jul 16, 2018 · 3 comments
Assignees
Labels
Webpack webpack study

Comments

@16slowly
Copy link
Owner

16slowly commented Jul 16, 2018

几个核心概念

  • context: 定义上下文,基础目录,需要打包的文件的绝对路径,将从中解析出入口文件及 loader 执行的目标
  • entry: 定义 webpack 打包的入口文件
    • app: 主入口文件,可以配置为一个数组,即多个入口文件
    • vendor: 分离第三方依赖库,允许使用 CommonsChunkPlugin(已为 SplitChunksPlugin) 从应用程序的 bundle 文件中提取 vendor 引用到 vendor 的 bundle 文件中,并把引用 vendor 的部分替换为 __webpack_require__() 调用。
  • output: 定义存放打包之后的文件的路径
  • plugins: 插件,增强 webpack 打包功能,如动态生成 html 文件的 HtmlWebpackPlugin 等。
  • resolve: 定义模块如何被解析
    • modules:定义被解析的模块
    • extensions: 扩展
    • alias: 创建 require 或 import 的别名,让编码过程中的模块引用更简单
  • loader: webpack 只能识别 javascript, 除此之外的文件需要用不同的 loader 进行预处理,比如图片使用 url-loader 或 file-loader, css 需要用 css-loader, 在 module 中进行定义。
@16slowly 16slowly added the Webpack webpack study label Jul 16, 2018
@16slowly 16slowly self-assigned this Jul 16, 2018
@16slowly
Copy link
Owner Author

16slowly commented Jan 18, 2019

常用插件

插件是 webpack 功能的核心,插件几乎活跃在整个 webpack 编译过程中,它可以在 webpack 构建系统中注册钩子,访问/修改编译器,并在必要时刻注入部分代码帮助完善一些辅助功能。

HtmlWebpackPlugin

生成 index.html 的 html5 文件, 该 html 文件包含了每次编译之后生成带有 hash 值的 bundle 文件,可直接指定一个已自定义好的 index.html。

常用配置项:

  • filename: html 文件名
  • template:指向自定义的 .html,如 SPA 下用于渲染组件,包含有 app 根节点的 index.html 文件.
  • minify: 对 .html 的压缩处理,去空格,删除 script 标签的 type 属性,link 标签的 style 属性等, 为了便于 dev 环境下的调试,一般根据开发环境进行配置。
  • favicon: 网页 favicon,
  • title: 网页 title,
  • inject: truebody | head, false, 默认 inject bundle 文件到 body 标签的底部,
  • more options

用 chunk 生成 .html 文件时的思考:

用 HtmlwebpackPlugin 生成 html 页面时,要注意 chunks 的顺序,默认情况下是按照 chunks 的字典顺序的反序排列(入口命名的字典顺序产生了 chunks 数组元素的 id 值,默认排序为 auto,反向排列 id 值)的,如果要改变,比如安装chunks的数组下标顺序,那么可以设置chunksSortMode : "none",或者设置一个排序函数。问题是,chunks的元素id一开始用排序方法与后来(设置或不设置)排序方法规则上有差异,造成了指定auto或者none都不能达到目的。最后,只能对入口做规范,比如让公用的打包为z开头的字母(保证为最后的chunk),再采用auto排序,可以做到公用chunk被首先加载

SplitChunksPlugin

see https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366

即提取项目中的公共模块,对于第三方库将最终合成一个 vendor 文件, 该文件能够在页面加载的最开始被加载一次,此后便存入到缓存中,每次访问,浏览器能迅速从缓存中取出,以提升加载速度。

在 webpack v4 里,直接开箱即用,默认切割规则为:

  1. 来自于 node_modules 或可以被共享的模块。
  2. 大于 30kb 的新块。
  3. 按需加载模块的最大并行请求数小于或等于 5。
  4. 初始页面的并行请求数小于或等于 3。

满足最后两个条件时,将选择最大的块。

配置项

  • .chunks
  • initial: 是否是非动态引入或为共享模块?是否是动态引入且为共享模块?是否是动态引入但不为共享模块?
  • async: 只 optimization 动态引入的模块,其他类型模块不 optimization 。
  • all: 根据模块划分,生成不同的 bundle 并进行共享。
  • minChunks: 规定被至少共享多少次才被 optimization, 切割针对至少被共享 minChunks 次的模块,默认次数为 1(推荐为 1),
  • cacheGroups:定义需要缓存的模块,配置会覆盖之外的普通配置
    • enforce: 忽略 minChunks, minSize, maximum requests 的定义, 始终为该缓存组创建块。
    • reuseExistingChunk: 尝试重用已存在的块。
    • name: 定义块名,相同名字的块将会被合并。
    • priority: 此 cacheCroups 的优先级,数值越高,某些块越有可能被打包进该 cacheGroup。
    • test: 确定该 cacheGroup 的范围。如只包含 node_modules 里的模块,则为 /[\\/]node_modules[//\]/

@16slowly
Copy link
Owner Author

16slowly commented Jan 18, 2019

功能

1. Code Splitting && Cache

  • entry: 设置多个入口文件,根据入口文件进行切割
    • 存在模块多次复用的问题
    • 不够灵活
  • 使用 SplitChunksPlugin (webpack v4 默认自动开启)
  • 代码中使用动态引入
  • 对模块进行 preload, prefetch(webpack 4.6.0+, see https://medium.com/webpack/link-rel-prefetch-preload-in-webpack-51a52358f84c)
  • 使用缓存 ,提升页面加载速度,需要保证模块能最大可能地被浏览器缓存,被复用。在 Code Splitting 阶段,通过配置,对第三方模块进行完整抽离(不受其他经常变化的文件影响),即生成带有固定不变 hash 值的文件名,保证浏览器初次加载就能缓存这部分模块。
optimization: {
    splitChunks: {
       cacheGroups: {
            vendors: {
                 chunks: 'all',
                 test: /[\\/]node_modules[\\/]/,
                 priority: -10,
            },
       }
    }
}

2. Hot Module Replacement

开发过程中,当对代码进行修改并保存后,webpack 将自动对代码进行打包,并将新块发送到浏览器,浏览器通过新的模块替换老的模块,实现在不刷新浏览器的前提下对应用进行更新。

配合 style-loader, css-loader 使用

使用 webpack-dev-server

const webpackDevServer = require('webpack-dev-server')
const webpack = require('webpack')
const config = require('./webpack.config.js')

const options = {
  contentBase: './dist',
  hot: true,
  host: 'localhost'
};

webpackDevServer.addDevServerEntrypoints(config, options)

配合 express 的 local server

const express = require('express')
const webpack = require('webpack')
const webpackHotMiddleware = require('webpack-hot-middleware')

const app = express()
const webpackConfig = require('./webpack.config')

const compiler = webpack(webpackConfig)
const webpackDevMiddleware = require('webpack-dev-middleware')(compiler, { //options })

app.use(webpackDevMiddleware)
app.use(webpackHotMiddleware(compiler))

3. 异步加载

通过一个 installedChunks 哈希表标识拆分后的 chunk 是否已经被加载, 未被加载则动态生成 script 标签进行加载

    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');

    script.type = 'text/javascript';
    script.charset = 'utf-8';
    script.async = true;
    script.src = __webpack_require__.p + "" + chunkId + "." + ({"0":"pageA","1":"pageB","3":"vendor"}[chunkId]||chunkId) + "." + {"0":"e72ce7d4","1":"69f6bbe3","2":"9adbbaa0","3":"53fa02a7"}[chunkId] + ".js";
      head.appendChild(script);

4. 静态资源缓存问题

场景:托管在阿里云上的静态图片资源,替换图片时,图片内容变了但图片名字没变,替换完成进行预览,看到的图片还是原来的图片。
原因: 浏览器缓存机制导致。浏览器通过资源名判断资源是否已经请求过,因为图片资源名字没有变化,所以就算替换了图片,浏览器用的资源还是缓存的资源,并不会请求新的图片。
解决办法:
利弊:

5. 根据配置重命名图片

待完善

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Webpack webpack study
Projects
None yet
Development

No branches or pull requests

1 participant