webpack学习总结

一、 webpack构建流程

Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:

  1. 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数
  2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译
  3. 确定入口:根据配置中的 entry 找出所有的入口文件
  4. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
  5. 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
  6. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
  7. 出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统

在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。

总结来说:

  1. 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler
  2. 编译:从 Entry 出发,针对每个 Module 串行调用对应的 Loader 去翻译文件的内容,再找到该 Module 依赖的 Module,递归地进行编译处理
  3. 输出:将编译后的 Module 组合成 Chunk,将 Chunk 转换成文件,输出到文件系统

二、 webpack打包入口

入口可以使用 entry 字段来进行配置,webpack 支持配置多个入口来进行构建。

Webpack资源入口,表示它是从哪个JS文件开始打包的。Webpack要找到这个文件,是通过context和entry这两个参数。

context是一个绝对路径,是基础目录的意思。entry是一个相对路径,它与context拼接起来,就是Webpack打包的入口文件了。

Webpack的资源入口与出口是紧密相关的。

2.1 入口entry是字符串形式

module.exports = {
  entry: './src/index.js' 
}

// 上述配置等同于
module.exports = {
  entry: {
    main: './src/index.js'
  }
}

2.2 入口entry是数组形式

module.exports = {
  entry: ['core-js/stable', 'regenerator-runtime/runtime', './a.js'],
};

它表示的含义是数组最后一个文件是资源的入口文件,数组其余文件会预先构建到入口文件。

上面的配置和下面是等效的。

// a.js
import 'core-js/stable';
import 'regenerator-runtime/runtime';
// webpack.config.js
module.exports = {
  entry: './a.js',
};

数组形式的入口本质还是一个入口。

2.3 入口entry是对象形式

入口entry是对象形式的又称之为多入口配置。之前我们讲的都是单入口的配置,本质上打包后生成一个JS文件。

多入口配置,本质上打包后生成多个JS文件。

const path = require('path');  
module.exports = {
  entry: {
    app: ['core-js/stable', 'regenerator-runtime/runtime', './a.js'],
    vendor: './vendor'
  },
  output: {
    path: path.resolve(__dirname, ''),
    filename: '[name].js'
  },
  mode: 'none'
};

上方的配置分别从两个入口文件打包,每个入口文件各自寻找自己依赖的文件模块打包成一个JS文件,最终得到两个JS文件。

2.4 入口entry函数形式

函数形式的入口,Webpack取函数返回值作为入口配置,返回值是上述3种之一即可。

函数形式的entry,可以用来做一些额外的逻辑处理,不过在自己搭脚手架的很少使用。

三、 webpack打包输出

output就是资源出口配置项。output是一个对象,它有几个重要的属性filename、path、publicPath和chunkFilename。

const path = require('path');  
module.exports = {
	output: {
		// 目标输出目录 path 的绝对路径。
		// path: '/dist',
		path: path.resolve(__dirname, './dist'),
		// filename 用于输出文件的文件名。
		filename: '[name].[hash:8].js'
	}
};

3.1 Webpack的output.filename

filename是打包后生成的资源名。

filename除了可以是一个文件名称,也可以是相对地址,例如’./js/bundle.js’。

最终打包输出的文件是path绝对路径与filename的拼接后的地址。

filename支持类似变量的方式生成动态文件名,例如:

  • [hash]-bundle.js,其中方括号很像占位符,hash表示特定的动态值。
  • [name]表示的是chunk的名称,chunk这个概念可以单独写一节,简单理解的话就是打包过程中,一个资源入口代表一个chunk,一个异步模块资源也代表一个chunk

其中字符串和数组形式的entry,output.filename的[name]值都是main。

特定动态值还有[hash]、[chunkhash]和[contenthash]等

  • hash是根据打包中所有的文件计算出的hash值。在一次打包中,所有出口文件的filename获得的[hash]都是一样的。
  • chunkhash是根据打包过程中当前chunk计算出的hash值。如果Webpack配置是多入口配置,那么通常会生成多个chunk,每个chunk对应的出口filename获得的[chunkhash]是不一样的。这样可以保证打包后每一个JS文件名都不一样
  • contenthash有点像chunkhash,是根据打包时CSS内容计算出的hash值。一般在使用提取CSS的插件的时候,我们使用contenthash
    plugins:[
        new miniExtractPlugin({
            filename: 'main.[contenthash:8].css'
        })
    ]
    

3.2 Webpack的output.path

path表示资源打包后输出的位置,该位置地址要是绝对路径。如果你不设置它,webpack4默认为dist目录。

需要注意的是,path输出路径表示的是在磁盘上构建生成的真实文件存放地址。我们在开发时,一般会用webpack-dev-server开启一个本地服务器,这个服务器可以自动刷新和热加载等,它生成的文件是在内存中而不是在电脑磁盘。该内存中的文件路径,我们会用Webpack配置文件的devServer配置项的publicPath表示,它虚拟映射了电脑磁盘路径。

3.3 Webpack的output.publicPath

output中的publicPath表示的是资源访问路径。

  • path: 资源输出位置表示的是本次打包完成后,资源存放的磁盘位置。
  • publicPath:资源存放到磁盘了,浏览器如何知道该资源存放在什么位置呢?这个时候需要我们指定该资源的访问路径,这个访问路径就是用output.publicPath来表示的

output.publicPath的表示形式有两大类:相对路径与绝对路径。

3.3.1 相对路径

相对路径又可以分类两种情况,第一种,它相对于当前浏览的HTML页面路径取值的。

1.)output.publicPath以"./“或”…/"等开头,表示要访问的资源以当前页面url作为基础路径。

  publicPath: ""  // 资源的访问地址是https://www.apple.com/ipad/bundle-3fa2.js
  publicPath: "../dist/"  // 资源的访问地址是https://www.apple.com/dist/bundle-3fa2.js
  publicPath: "./dist/"  // 资源的访问地址是https://www.apple.com/ipad/dist/bundle-3fa2.js

2.)output.publicPath以"/"开头,表示要访问的资源以当前页面的服务器地址作为基础路径。

 publicPath: "/"  // 资源的访问地址是https://www.apple.com/bundle-3fa2.js。
 publicPath: "/dist/"  // 资源的访问地址是https://www.apple.com/dist/bundle-3fa2.js。

3.3.2 绝对路径

output.publicPath的值以HTTP协议名称开始。一般在使用CDN的时候,因为CDN的域名与我们自己服务器的域名不一样,我们会采用这种方式。

Web中常见的协议名称有http和https,例如我的网站 https://www.jiangruitao.com/ 的协议名称就是https。

还有一种叫做相对协议的形式,它以 // 开头,也就是省略了前面的https:或http:。

在使用相对协议的时候,浏览器会对前页面使用的协议名称与相对协议拼接。

下面看一下output.publicPath的值以协议开始的例子,在以协议开始的publicPath时,资源的访问地址是publicPath代表的绝对路径加上资源名称。

  publicPath: "https://cdn.apple.net/"  // 资源的访问地址是https://cdn.apple.net/bundle-3fa2.js
  publicPath: "http://cdn.apple.net/"  // 资源的访问地址是http://cdn.apple.net/bundle-3fa2.js
  publicPath: "//cdn.apple.net/dist/"  // 资源的访问地址是https://cdn.apple.net/dist/bundle-3fa2.js

3.4 Webpack的output.chunkFilename

chunkFilename也是用来表示打包后生成的文件名,那它和filename有什么区别呢?

它表示的是打包过程中非入口文件的chunk名称,通常在使用异步模块的时候,会生成非入口文件的chunk。

四、 Webpack预处理器loader

预处理器loader本质是一个函数,它接受一个资源模块,然后将其处理成Webpack核心能使用的形式。

webpack 中提供一种处理多种文件格式的机制,便是使用 loader。我们可以把 loader 理解为是一个转换器,负责把某种文件格式的内容转换成 webpack 可以支持打包的模块。

4.1 postcss-loader

自动检测兼容性给各个浏览器加个内核前缀的插件

配置 .browserslistrc ,标明支持的浏览器:

# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries

# You can see what browsers were selected by your queries by running:
#   npx browserslist

> 0.5%
last 2 versions
not dead
IE 9-11
Firefox >= 38
Chrome >= 43
Edge 13
Safari >= 8

配置 postcss.config.js,配置 postcss-loader参数:

module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}

4.2 css-loader

加载.css文件

4.3 style-loader

使用<style>将css-loader内部样式注入到我们的HTML页面

4.4 less-loader

加载 .less 文件

4.5 MiniCssExtractPlugin.loader

配合 MiniCssExtractPlugin 插件,将 css 提取到文件中。

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader
                    },
                    {
                        loader: 'css-loader'
                    },
                    {
                        // 自动检测兼容性给各个浏览器加个内核前缀的插件
                        loader: 'postcss-loader'
                    }
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin(
            {
                filename: '[name].[hash:8].css',
                chunkFilename: '[id].css'
            }
        ),
    ]
};

4.6 babel-loader

Babel是一个JavaScript编译器,能够让我们放心的使用新一代JS语法。

配置 .babelrc 或者 options

使用时需要安装相关相关依赖:

npm install babel-loader @babel/core @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime @babel/preset-env @babel/runtime -D

相关配置如下:

module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: [
                                "@babel/preset-env"
                            ],
                            plugins: [
                                "@babel/plugin-proposal-class-properties",
                                "@babel/plugin-syntax-dynamic-import"
                            ]
                        }
                    }
                ]
            }
        ]
    }
};

4.7 html-loader

解析 .html

4.8 url-loader

url-loader会把我们的图片使用base64的形式编码成另外一种字符串,网页是可以识别这种编码的东西的,这样的好处是,它减少了图片的请求,你只要请求回了这个页面,图片也就过来了,可以减少网络的请求,但是如果图片过大,这个字符串就会变得特变大,让加载的文件变得特别大。

webpack 5已经弃用url-loader、file-loader,使用asset modules代替(https://blog.csdn.net/gtLBTNq9mr3/article/details/117173678)

4.9 parser

可用作 url-loader 的功能。

{
    test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot|webp)$/i,
    type: 'asset',
    parser: {
        dataUrlCondition: {
            maxSize: 1024 * 10
        }
    }
}

五、 Webpack插件plugin

通常plugins数组每一个元素都是插件构造函数New出来的一个实例,根据每一个插件的特点,可能会需要向其参数里传递各种配置参数,这个时候需要参阅该插件的文档来进行配置。

现在广泛使用的插件都有默认的参数,可以免去配置,只有在需要特殊处理时,我们进行手动配置参数。

5.1 CleanWebpackPlugin

删除文件

默认删除dist目录,也可使用自定义配置:

const CleanWebpackPlugin = require('clean-webpack-plugin');

new CleanWebpackPlugin(
	['dist/main.*.js','dist/manifest.*.js'], // 匹配删除的文件
	{
		root: path.resolve(__dirname), // 根目录
		verbose: true, // 开启在控制台输出信息
		dry: false // 启用删除文件
	}
)


5.2 HtmlWebpackPlugin

将 webpack中entry配置的相关入口chunk 和 extract-text-webpack-plugin抽取的css样式

插入到该插件提供的template或者templateContent配置项指定的内容基础上生成一个html文件,具体插入方式是将样式link插入到head元素中,script插入到head或者body中。

const HtmlWebpackPlugin = require('html-webpack-plugin');

new HtmlWebpackPlugin({
    template: './src/index.html',
    filename: 'index.html',
    favicon: `node_modules/@cube/cf-theme/${helpers.consoleTheme}/theme/default/images/favicon.ico`,
    framework_resource_dir: helpers.frameworkServerBase,
    business_resource_dir: helpers.getPublicServerBase(isProd),
    inject: false,
    // html压缩
    minify: {
        collapseWhitespace: true, // 移除空格
        removeComments: true, //移除注释
    }
})
  • title: 用来生成页面的 title 元素
  • filename: 输出的 HTML 文件名,默认是 index.html, 也可以直接配置带有子目录。
  • template: 模板文件路径,支持加载器,比如 html!./index.html
  • inject: true | ‘head’ | ‘body’ | false ,注入所有的资源到特定的 template 或者 templateContent 中,如果设置为 true 或者 body,所有的 javascript 资源将被放置到 body 元素的底部,‘head’ 将放置到 head 元素中。
  • favicon: 添加特定的 favicon 路径到输出的 HTML 文件中。
  • minify: {} | false , 传递 html-minifier 选项给 minify 输出
  • hash: true | false, 如果为 true, 将添加一个唯一的 webpack 编译 hash 到所有包含的脚本和 CSS 文件,对于解除 cache 很有用。
  • cache: true | false,如果为 true, 这是默认值,仅仅在文件修改之后才会发布文件。
  • showErrors: true | false, 如果为 true, 这是默认值,错误信息会写入到 HTML 页面中
  • chunks: 允许只添加某些块 (比如,仅仅 unit test 块)
  • chunksSortMode: 允许控制块在添加到页面之前的排序方式,支持的值:‘none’ | ‘default’ | {function}-default:‘auto’
  • excludeChunks: 允许跳过某些块,(比如,跳过单元测试的块)

minify各配置项用法说明:

  • removeComments(默认值false):清理html中的注释
  • collapseWhitespace(默认值false):清理html中的空格、换行符
  • minifyCSS(默认值false):压缩html内的样式
  • minifyJS(默认值false):压缩html内的js
  • removeEmptyElements(默认值false)清理内容为空的元素,但这个功能慎用,空元素可能用于占位或在js逻辑里有填充动作
  • caseSensitive(默认值false):以区分大小写的方式处理自定义标签内的属性
  • removeScriptTypeAttributes(默认值false):去掉script标签的type属性
  • removeStyleLinkTypeAttributes(默认值false):去掉style和link标签的type属性

5.3 MiniCssExtractPlugin

提取 css 放到文件中,需要配合 MiniCssExtractPlugin.loader 使用

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

new MiniCssExtractPlugin(
    {
        filename: '[name].[hash:8].css',
        chunkFilename: '[id].css'
    }
)

5.4 OptimizeCssAssetsPlugin

优化 css 资源,压缩 css 文件

const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
new OptimizeCssAssetsPlugin();

5.5 ProvidePlugin

webpack配置ProvidePlugin后,在使用时将不再需要import和require进行引入,直接使用即可。

new webpack.ProvidePlugin({
  $: 'jquery',
  jQuery: 'jquery',
});

const time = require('../time/time.js');
import './hello.word.css';

function writeToHtml(){
    const world = 'hello world';
    console.log(world);
    console.log(time);
    const htmlElement = $('.container');
    const htmlElement_2 = jQuery('.container');
    console.log(htmlElement);
    console.log(htmlElement_2);
}

writeToHtml();

5.6 CopyWebpackPlugin

单个文件或整个目录复制到构建目录

const CopyWebpackPlugin = require('copy-webpack-plugin');

new CopyWebpackPlugin({
    patterns: [
        {
            from: 'src/config'
        },
        {
            from: 'src/img',
            to: 'img'
        }
    ]
}),

5.7 DefinePlugin

允许创建一个在编译时可以配置的全局常量

new webpack.DefinePlugin({
    VERSION: JSON.stringify('1-2-4')
})
const time = require('../time/time.js');
import './hello.word.css';

function writeToHtml(){
    const world = 'hello world';
    console.log(world);
    console.log(time);
    const htmlElement = $('.container');
    const htmlElement_2 = jQuery('.container');
    console.log(htmlElement);
    console.log(htmlElement_2);
    console.log(VERSION);
}

writeToHtml();

5.8 体积分析:使用webpack-bundle-analyzer

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

module.exports = {
    plugins: [
        new BundleAnalyzerPlugin()
    ]
};
  • 构建完成后会在 8888 端口展示大小
  • 了解更多
  • 可以分析哪些问题?
    1. 依赖的第三方模块文件大小
    2. 业务里面的组件代码大小

5.9 速度分析:使用speed-measure-webpack-plugin

使用:将默认配置文件包裹起来

const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

const smp = new SpeedMeasurePlugin();

//将默认的webpack配置文件包裹起来
const webpackConfig = smp.wrap({
  plugins: [
    new MyPlugin(),
    new MyOtherPlugin()
  ]
});
  • 了解更多
  • 速度分析插件作用
    1. 分析整个打包总耗时
    2. 每个插件和loader的耗时情况

六、 webpack优化配置optimization

6.1 配置js压缩

配置了 OptimizeCssAssetsPlugin ccs压缩后,webpack就不会自动压缩js,需自己配置。

module.exports = {
  // 优化配置
  optimization: {
        // 自己配置 js 压缩,配置了 OptimizeCssAssetsPlugin ccs压缩后要想压缩js,必须配置此处
        minimize: true,
        minimizer: [
            new TerserPlugin()
        ]
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值