webpack笔记

1. webpack的基本使用

在webpack.config.js文件中

const path = require('path');

module.exports = {
    // 打包入口文件
    entry: './src/main.ts',
    // 打包输入文件
    output: {
        // 文件名
        filename: 'build.js',
        // 放置路径
        path: path.resolve(__dirname, './dist'),
    },
    // 配置后import导入时可以不用写对应文件扩展名
    resolve:{
       extensions:['.js','.ts','.jsx']
    }
}

2. loader的作用

Loader和Plugin的区别

  • Loader是用于特定的模块类型进行转换。
  • Plugin可以用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入等

除了 JavaScript,如果需要用 webpack 打包其他类型的文件,都需要配置响应的 loader,所以 loader 是增强扩宽了webpack 的功能。下面用的loader或其它插件都需要先使用npm安装到项目的开发环境中, 如要打包 css 文件,就需要安装 css-loader。

在webpack.config.js文件中

配置解析css的loader

const path = require('path');

module.exports = {
     // 省略上面内容
    ...,
    // 配置loader
    module: {
        rules: [
            {
                // test用于对resource(资源)进行匹配,通常设置为正则表达式
                test: /\.css$/,
                // 配置用于打色的loader
                // 完整写法,可以在对象中配置其它的东西
                use: [
                    {loader: 'style-loader'},
                    {loader: 'css-loader'},
                ],
                // 简写方式
                // use: [
                //     // 1.css-loader 只是解决了css语法解析的问题,只用css-loader是不能将样式加载到页面上的,还需要 style-loader。
                //     // 2.loader的配置顺序和他的加载顺序是相反的,所以 style-loader 必须放在 css-loader 之前!!!
                //     'style-loader',
                //     'css-loader',
                // ]
            }
        ]
    }
}

配置解析less的loader

const path = require('path');

module.exports = {
     // 省略上面内容
    ...,
    // 配置loader
    module: {
        rules: [
           // 省略上面内容
           ...,
            {
                test: /\.less$/,
                use: [
                    {loader: 'style-loader'},
                    {loader: 'css-loader'},
                    {loader: 'less-loader'},
                ]
            }
        ]
    }
}

配置postcss的loader

const path = require('path');

module.exports = {
    // 省略上面内容
    ...,
    // 配置loader
    module: {
        rules: [
            // 省略上面内容
            ...,
            {
                test: /\.less$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader',
                    'postcss-loader'
                ]
            }
        ]
    }
}

配置了postcss-loader,还需要配置额外的postcss-preset-env插件才可以生效
新建 postcss.config.js文件

module.exports = {
    plugins: {
        'postcss-preset-env'
    }
}

配置处理图片的loader

type的取值及区别

  • asset: 通用资源类型。推荐这个取值。但需要额外配置才更合理。
    1. 小图片用base64,大图片用单独导出url
    2. 增加parser配置,见下面代码
  • asset/resource: 发送一个单独的文件并导出url,把url设置到src或background的url中。之前通过file-loader实现。缺点:每个图片加载都会网络请求两次
  • asset/inline: 将图片base64编码,并且直接把编码后的源码放到打包后的js文件中。之前通过file-loader实现。缺点:造成js文件非常大,下载js本身比较耗时
const path = require('path');

module.exports = {
    // 省略上面内容
    ...,
    // 配置loader
    module: {
        rules: [
            // 省略上面内容
            ...,
            // 使用webpack内置模块打包图片资源
            {
                test: /\.(png|jpe?g|svg|gif)$/,
                type: 'asset',
                // asset类型时,设置图片小于xx时使用base64,大于xx时用导出url
                parser: {
                    dataUrlCondition: {
                        maxSize: 60 * 1024 // 60kb
                    }
                },
                generator: {
                    // 表示:用图片名+webpack生成的hash值+文件扩展名+文件参数命名的图片打包到images文件中
                    filename: 'images/[name][hash][ext][query]'
                }
            }
        ]
    }
}

3. webpack插件

安装对应插件
CleanWebpackPlugin: 重新打包时,自动删除dist文件夹
HtmlWebpackPlugin: 打包时,生成指定模板和网站名称的html文件

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    // 省略上面内容
    ...,
    // 插件
    plugins: [
        // 重新打包时,自动删除之前打包的文件夹
        new CleanWebpackPlugin(),
        // 自动生成html文件
        new HtmlWebpackPlugin({
            // 指定生成html的模板
            template: path.resolve(__dirname, './src/index.html'),
            // 指定网站的名称
            title: '网站名称'
        })
    ]
}

4. Mode配置

作用:可以告诉webpack使用相应模式的内置优化

  • 默认值:production
  • 可选值:none、development、production

区别:
development:开发模式。会将DefinePlugin中的process.env.NODE_ENV的值设置为development。为模块和分包(chunk)启用有效(看的懂)的名字。
production:生产模式。会将DefinePlugin中的process.env.NODE_ENV的值设置为production。为模块和分包(chunk)启用混淆的名字。

module.exports = {
    // 配置是 开发环境development或生产环境production
    mode: 'development'
}

5. webpack开启本地服务器

安装webpack-dev-server
在编译之后不会写入到任何输出文件,而是将bundle文件保留在内存中,事实上它使用了memfs的库

module.exports = {
    // 省略上面内容
    ...,
   // 安装webpack-dev-server后,开启devServer配置
    devServer:{
        // 开启HMR模块热替换,默认是开启的
        hot:true,
        // 此配置,其它人可以通过本地电脑ip来访问这个网站
        host:'0.0.0.0',
        // 自定义端口号
        port: 3000,
        // 开发阶段使用代理解决跨域问题。生产阶段一般使用Nginx解决跨域
        proxy: {
             // 遇到/api开头的请求路径时,代理到下面target配置的地址
             '/api':{
               // 服务器地址,如http://localhost:5000
               tatget:'http://localhost:5000',
               pathRewrite:{
                   // 把以/api开头的这个路径替换为空,相当于去掉/api
                   '^/api':''
               },
              // 虽然上面代理了,但服务器接收的host属性地址还是http://localhost:3000,如果服务器设置了检验,这个请求还是失败的,配置changeOrigin属性,服务器接收的host属性的地址就是http://localhost:5000
              changeOrigin:true
             }
         },
        // 出现没有配置路由时,自动重定向到http://localhost:3000,避免出现404页面
        histroyApiFallback:true
    }
}

6. 使用source-map查看打包后的文件

devtool配置项,不配置默认就是none
最佳实践

  • 开发阶段:source-map/cheap-module-source-map
  • 生成阶段:source-map/cheap-module-source-map
  • 线上阶段:false/none
module.exports = {
    // 省略上面内容
    ...,
    // 配置打包后代码是否生成source-map来解析
    devtool: 'source-map'
}

7. 浏览器兼容性 browserslist

  • 打包时为了兼容不同浏览器,可以配置browserslist
  • 可以设置在package.json中,也可以单独创建一个.browserslistrc配置在其中

配置在package.json文件

"browserslist": {
        // 市场占有率大于0.5%
        > 0.5%
        // 最新的两个版本
        last 2 version
        // 24个月还在维护的浏览器
        not dead
    }

8. 配置babel-loader

const path = require('path');

module.exports = {
    // 省略上面内容
    ...,
    // 配置loader
    module: {
        rules: [
            // 省略上面内容
            ...,
            // 使用babel转化js
            {
                text: /\.js$/,
                use: [
                    'babel-loader'
                ]
            },
            //使用babel转化react的jsx
            {
                text: /\.jsx?$/,
                use: [
                    'babel-loader'
                ]
            },
            //使用babel转化ts
            {
                text: /\.ts$/,
                use: [
                    'babel-loader'
                ]
            },
        ]
    }
}

配置了babel-loader,还需要配置额外的@babel/preset-env预设才可以生效
新建 babel.config.js文件

module.exports = {
    presets: [
        '@babel/preset-env'
    ]
}

polyfill

相当于打补丁,针对浏览器不支持的语法
需要安装core.js和regenerator-runtime

在babel.config.js文件中

module.exports = {
    presets: [
        ['@babel/preset-env', {
            // useBuiltIns有三个取值。
            // false:打包后文件不使用polyfill进行适配,可不设置corejs版本
            // usage:根据源代码出现的语法,自动检测所需要的polyfill,打包后文件也会比较小一些
            // entry:适用于第三方库本身使用了某些polyfill特性,需要在入口文件添加 import 'core-js/stable',import 'regenerator-runtime/runtime'
            useBuiltIns: 'usage',
            corejs: 3.8
        }]
    ]
}

ts的编译

在babel.config.js文件中

module.exports = {
    presets: [
        // 编译es6新特性的预设
        '@babel/preset-env',
        // 编译react的预设
        '@babel/preset-react',
        // 编译ts的预设
        '@babel/preset-typescript',
    ]
}

9. webpack性能优化

9.1. 分包处理

  • 多入口起点:配置多个打包入口文件,目前vue和react项目都是单入口文件,不推荐
  • 动态导入:使用import()语法,使用最多
module.exports = {
    // 省略上面内容
    ...,
    // 打包输入文件
    output: {
        // 文件名
        filename: 'build.js',
        // 放置路径
        path: path.resolve(__dirname, './dist'),
        // 设置分包后的文件名,默认情况下name是该文件的完整路径,可在import()中自定义打包后的文件名
        chunkFilename: '[name]_chunk.js,
    }
}
import(/*webpackChunkName:'文件名'*/ './src/router/about')
  • 自定义分包
module.exports = {
    // 省略上面配置
    ...,
    //打包输入文件
    output: {
        //文件名
        filename: 'build.js',
        //放置路径
        path: path.resolve(__dirname, './dist'),
        // 设置分包后的文件名,默认情况下name是该文件的完整路径,可在import()中自定义打包后的文件名
        chunkFilename: '[name]_chunk.js'
    },
    // 优化配置
    optimization: {
        // 设置生成chunkId的算法
        // develoment模式下默认是named,表示完整文件名
        // production模式下默认是deterministic,确定性的,在不同的编译中变成短数字id
        chunkIds: 'named',
        splitChunks: {
            chunks: 'all',
            // 当包大于指定大小时,继续拆包,下面表示大于20kb的继续拆包
            maxSize: '20000',
            // 将包拆分成不小于10kb的包
            minSize: '10000',
            // 自己对需要进行拆包的内容分包
            cacheGroups: {
                // 自定义key
                a: {
                    test: '/node_modules/',
                    filename: '[name]_node_modules.js',
                },
                b: {
                    test: '/utils/',
                    filename: '[name]_utils.js',
                }
            }
        }
    }
}

9.2. 分包处理之prefetch和preload

  • prefetch:预获取,将来某些导航下可能需要的资源,在父包加载结束后,浏览器闲置时下载,推荐
  • preload:预加载,当前导航下可能需要的资源,和父包以并行方式开始加载
import(
/*webpackChunkName:'文件名'*/ 
/*webpackprefetch:true*/
'./src/router/about')

9.3. 分包处理之CDN内容分发网络

它是指通过相互连接的网络系统,利用最靠近每个用户的服务器,更快,更可靠的将音乐,图片,视频,应用程序及其他文件发送给用户,提供高性能,可扩展性及低成本的网络内容传递给用户
在output中配置购买的CDN服务器地址

module.exports = {
    // 省略上面配置
    ...,
    //打包输入文件
    output: {
        //文件名
        filename: 'build.js',
        //放置路径
        path: path.resolve(__dirname, './dist'),
        // 设置分包后的文件名,默认情况下name是该文件的完整路径,可在import()中自定义打包后的文件名
        chunkFilename: '[name]_chunk.js',
        // 在output中配置购买的CDN服务器地址
        publicPath: 'CDN服务器地址'
    },
    // 在开发中一般使用第三方库的CDN地址,有两步操作
    // 第一步,配置排除不用打包的文件
    externals: {
        axios: 'axios',
        react: 'React'
    }
}

第二步,在html文件中手动添加排除打包的第三方库的CDN地址

<body>
    <script src='axios的CDN地址'></script>
    <script src='react的CDN地址'></script>
</body>

9.4. 优化之提取css文件

  • 使用MiniCssExtractPlugin插件可以把css单独打包成一个文件
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
    // 省略上面内容
    ...,
    // 配置loader
    module: {
        rules: [{
            // 简写方式
            use: [
                //内联方式添加到网页中
                // 'style-loader',
                // 单独打包到一个独立文件
                MiniCssExtractPlugin.loader,
                'css-loader',
            ]
        }]
    },
    // 插件
    plugins: [
        // css分包插件
        new MiniCssExtractPlugin({
            filename: 'css/[name].css'
        })
    ]
}

10. 前端项目中的优化

  1. 首屏加载速度
    1.1 减少首屏资源体积(收益比较大)

    • 打包工具的压缩-打包工具已经做好了
    • 异步加载,如体积比较大,但又不是马上要用的功能,就可以异步加载
    • 更换新版本第三方库,使用支持按需导入的ESM的方式的版本,然后通过配置打包工具中的tree-shaking来实现删除无用代码的目的,减少打包体积
    • 能不用第三方库,就不用第三方库,比如一个简单的日期格式化
    • 编写代码简洁,规范,减少冗余代码,也能减少代码的体积
    • 合理配置需要转为base64的图片,大图片尽量不要转

    1.2 收益较小的优化

    • 减少简单数据的请求,尽量把小请求合并到大请求接口中
    • 可以把没有关联的多个请求接口,使用并行的方式进行请求
    • 页面dom元素较多时,可以实现瀑布流式的渲染方式
    • 使用骨架屏或loading,给用户提示,减少用户看着白屏的等待焦虑
  2. 操作速度和渲染速度

    • 避免一次性操作大量dom,可以使用长列表渲染和异步渲染
    • vue中,频繁切换显示隐藏使用v-show来渲染
    • vue或react中,循环添加key值
    • vue中,使用keep-alive来缓存组件
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 2018年8月25日更新,目前 webpack 已经更新值 4.17.1 ,本文所用到的各种库或多或少有些过时,跟...
    AizawaSayo阅读 1,781评论 0 2
  • 1.调试更容易(生成Source Maps) 开发总是离不开调试,方便的调试能极大的提高开发效率,不过有时候通过打...
    泽玲_d7fb阅读 2,860评论 0 0
  • 1. webpack介绍 本质上,webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具...
    WangLizhi阅读 4,755评论 0 1
  • webpack4笔记 快速了解几个基本的概念 mode 模式 通过选择 development, producti...
    假装没昵称阅读 2,773评论 0 1
  • 1、 Loader是什么? 1、我们之前打包的都是js文件,下面试试打包一个图片文件。 首先将一个图片文件放进sr...
    无争公子__阅读 3,471评论 0 0