Webpack5

一、Webpack基础

打包工具:将框架(React、Vue),ES6,Less/Sass等语法编译成浏览器能识别的JS、CSS;压缩代码、兼容性处理、提升代码性能等。

一、entry(入口)

指示Webpack 从哪个文件开始打包

二、output(输出)

指示Webpack打包完的文件输出到哪里去,如何命名等

三、loader(加载器)

webpack本身只能处理JS、JSON等资源,其他资源需要借助loader,webpack才能解析

四、plugins(插件)

扩展webpack的功能

五、mode(模式)

  • 开发模式:development
  1. 编译代码,使浏览器能识别运行
  2. 代码质量检查,梳理代码规范
  • 生产模式:production
  1. 优化代码运行性能
  2. 优化代码打包速度

javascript 复制代码
//webpack.config.js
const path = require("path");// nodejs核心模块,专门用来处理路径问题
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizePlugin = require('css-minimize-plugin');
const TerserWebpackPlugin = require("terser-webpack-plugin");
const os = require("os");//nodejs核心模块,直接使用

const threads = os.cpus().length;//cpu核数

module.exports = {
    //入口
    entry:"./src/main.js",//相对路径
    //输出
    output:{
        //所有文件的输出路径
        //_dirname nodejs的变量,代表当前文件的文件夹目录
        path:path.resolve(_dirname,"dist"),//绝对路径
        //入口文件打包输出文件名
        filename:"static/js/[main].js",
        //给打包输出的其他文件命名
        chunkFilename:"static/js/[name].chunk.js",
        //图片、字体等通过type:asset处理资源命名方式
        assetModuleFilename:"static/media/[hash:10][ext][query]",
        // 自动清空上次打包内容 原理:在打包前,将path整个目录内容清空,再进行打包
        clean: true,
    },
    //加载器
    module:{
        rules:[
        //loader的配置
            // css配置
            {
                test:/\.css$/, //只检测.css文件
                use:[
                    //执行顺序:从右都左(从下到上)
                    //"style-loader",// 将js中的css通过创建style标签添加html文件中生效
                    MiniCssExtractPlugin.loader,// 提取css成单独文件
                    "css-loader",// 将css资源编译成commonjs的模块到js中
                    {
                        loader:"postcss-loader",
                        options:[
                            postcssOptions:{
                                plugins:[
                                    "postcss-preset-env",//能解决大多数样式兼容性问题
                                ],
                            },
                        ],
                    },
                ]
            },
            // less配置
            {
                test:/\.less$/, 
                // loader:'xxx', //只能使用1个loader
                use:[// 使用多个loader
                    //"style-loader",// 将js中的css通过创建style标签添加html文件中生效
                    MiniCssExtractPlugin.loader,// 提取css成单独文件
                    "css-loader",// 将css资源编译成commonjs的模块到js中
                    {
                        loader:"postcss-loader",
                        options:[
                            postcssOptions:{
                                plugins:[
                                    "postcss-preset-env",//能解决大多数样式兼容性问题
                                ],
                            },
                        ],
                    },
                    "less-loader", // 将less编译成css文件
                ]
            },
            // Sass/Scss配置
            {
                test:/\.s[ac]ss$/, 
                use:[
                    //"style-loader",// 将js中的css通过创建style标签添加html文件中生效
                    MiniCssExtractPlugin.loader,// 提取css成单独文件
                    "css-loader",// 将css资源编译成commonjs的模块到js中
                    {
                        loader:"postcss-loader",
                        options:[
                            postcssOptions:{
                                plugins:[
                                    "postcss-preset-env",//能解决大多数样式兼容性问题
                                ],
                            },
                        ],
                    },
                    "sass-loader", // 将sass编译成css文件
                ]
            },
            // 图片配置
            {
                test:/\.(png|jpe?g|gif|webp|svg)$/,
                type:"asset",
                parser:{
                    dataUrlCondition:{
                        //小于10kb的图片转base64,优点:减少请求数量 缺点:体积会更大
                        maxSize:10*1024, // 10kb
                    },
                },
                generator:{
                    //输出图片名称  [hash:10] hash值取前10位
                    //filename: "static/images/[hash:10][ext][query]",
                },
            },
            // 字体图表及其他资源配置
            {
                test:/\.(ttf|woff2?|map3|map4|avi)$/,
                type:"asset/resourse",
                generator:{
                    //输出名称
                    //filename: "static/desia/[hash:10][ext][query]",
                },
            },
            // babel配置
            {
                test:/\.js$/,
                //exclude:/node_modules/, // 排除node_moudles下的文件,其他文件都处理
                include:path.resolve(_dirname,"../src"),// 只处理src下的文件,其他文件不做处理
                use:[
                    {
                        loader:"thread-loader",// 开启多进程
                        options:{
                            workers:threads, //进程数量
                        }
                    },
                    {
                        loader: "babel-loader",
                        options:{
                        //    //智能预设
                        //    presets: ["@babel/preset-env"],
                        cacheDirectoy:true,// 开启babel缓存
                        cacheCompression:false,// 关闭缓存文件压缩
                        plugins:["@babel/plugin-transform-runtime"],//减少代码体积
                    },               
                ],
            },
        ]
    },
    //插件
    plugins:[
        //ESLint的配置
        new ESLintPlugin({
            //检测哪些文件
            context: path.resolve(_dirname,"src"),
            exclude:"node_modules",// 默认值
            cache:true,//开启缓存
            cacheLocation:path.resolve(_dirname,"../mode_modules/.cache/eslintcache"),
            threads, //开启多进程和进程数量
        }),
        new HtmlWebpackPlugin({
            // 模板:以public/index.html文件创建新的html文件(自动引入打包输出的资源)
            template:path.resolve(_dirname,"public/index.html"),
        }),
        new MiniCssExtractPlugin({
            filename:"static/css/[main].css",
            chunkFilename:"static/css/[name].chunk.css",
        }),
        //new CssMinimizePlugin(),
        //new TerserWebpackPlugin({
        //    parallel:threads, //开启多进程和进程数量
        //}),
    ],
    optimization:{
        //压缩的操作
        minimizer:[
            //压缩css
            new CssMinimizePlugin(),
            //压缩js
            new TerserWebpackPlugin({
                parallel:threads, //开启多进程和进程数量
            }),
        ],
    },
    代码分割配置
    splitChunks:{
        chunks:"all",// 其他都用默认值
    },
    runtimeChunk:{
        name:(entrypoint) => `runtime~${entrypoint.name}.js`,
    },
    //开发服务器:不会输出资源,在内存中编译打包的
    devServer:{
        host:"localhost",// 启动服务器域名
        port:"3000",// 启动服务器端口号
        open:true, //是否自动打开浏览器
        hot:true, // 开启HMR(默认开启)
    },
    //模式
    mode:"development",
};

Eslint :可组装的Javascript和JSX检查工具(检测js和jsx语法的工具,可配置各项功能)

文档:https://eslint.nodejs.cn/docs/latest/use/getting-started

Babel :JavaScript编译器。主要用于将ES6语法编写的代码转换为向后兼容的JavaScript语法,以便能够运行在当前和旧版本的浏览器或其他环境中

javascript 复制代码
// package.json文件
"script":{
    "dev":"webpack serve --config ./config/webpack.dev.js",//启动开发服务器,内存编译打包没有输出
    "build":"webpack --config ./config/webpack.prod.js",//直接打包输出
}

生产环境:

**提取css成单独文件:**css打包到js文件中,当js文件加载时会创建一个style标签来生成样式,这样对网站的用户体验不好,会出现闪屏现象

解决:使用MiniCssExtractPlugin,提取css成单独文件,通过link标签加载

**样式兼容性处理:**postcss-loader

javascript 复制代码
//package.json文件
"browserslist":[
    //"ie >= 8",
    "last 2 version",
    "> 1%",
    "not dead"
]

**css压缩:**CssMinimizePlugin

二、Webpack优化

1.提升开发体验

SourceMap(源代码映射):用来生成源代码与构建后的代码一一映射的文件的方案,帮助我们更快找到错误根源。

开发模式:cheap-module-source-map

优点:打包编译速度快,只包含行映射 缺点:没有列映射

javascript 复制代码
// webpack.config.js
module.exports=[
    mode:"development",
    devtool:"cheap-module-source-map",
]

生产模式:source-map

优点:包含行、列映射 缺点:打包编译速度更慢

javascript 复制代码
// webpack.config.js
module.exports=[
    mode:"production",
    devtool:"source-map",
]

2.提升打包构建速度

(1)HotModuleReplacement(HMR:热模块替换)

在程序运行中,替换、添加或删除某个模块代码,就只有这个模块代码需要重新打包编译,其他模块不变,这样打包速度更快,无需重新加载整个页面。(开发环境)

(2)OneOf

javascript 复制代码
//加载器
module:{
    rules:[
        // loader的配置
        {
            //每个文件只能被其中一个loader配置处理
            oneOf:[
                ......
            ],
        },
    ],
},

(3)Babel、Eslint 对node_modules下的文件 include或exclude处理

(4)Cache:对Eslint检查和Babel编译结果进行缓存

每次打包时js文件都要经过Eslint检查和Babel编译,速度比较慢。可以缓存之前的Eslint检查和Babel编译结果,这样第二次打包时速度更快。(生产环境)

(5)多进程打包:开启电脑的多个进程同时干一件事,速度更快。注意:仅在特别耗时的操作中使用,因为每个进程启动就有大约600ms左右的开销。

javascript 复制代码
//nodejs核心模块,直接使用
const os = require("os");
//cpu核数
const threads = os.cpus().length;
javascript 复制代码
npm i thread-loader -D

3.减少代码体积

(1)Tree Shaking:用于移除JavaScript中的没有使用上的代码 注意:它依赖ES Module

webpack已经默认开启了这个功能,无需其他配置。

(2)减少babel生产文件的体积

Babel为编译的每个文件都插入了辅助代码,使代码体积过大。

Babel对一些公共方法使用了非常小的辅助代码,比如_extend。默认情况下会被添加到每一个需要它的文件中。可以将这些辅助代码作为一个独立模块,来避免重复引入。

@babel/plugin-transform-runtime:禁用了babel自动对每个文件的runtime注入,而是引入@babel/plugin-transform-runtime并且使所有辅助代码从这里引入

(3)压缩图片

本地项目静态图片需要压缩

image-minimizer-webpack-plugin:用来压缩图片的插件

4.优化代码运行性能

(1)代码分割Code Split

1.分割文件:将打包生成的文件进行分割,生成多个js文件

2.按需加载:需要哪个文件就加载哪个文件

打包代码时会将所有的js文件打包到一个文件中,体积太大了,如果只需要渲染首页,就应该只加载首页的js文件,其他文件不应该加载。

需要将打包生成的文件进行代码分割,生成多个js文件,渲染哪个页面就只加载某个js文件,这样加载的资源就少,速度就更快。

javascript 复制代码
document.getElementById("btn").onclick = function () {
    // import动态导入:会将动态导入的文件代码分割(拆分成单独模块),在需要使用的时候自动加载
    // /* webpackChunkName: "count" */ webpack魔法命名
    import(/* webpackChunkName: "count" */ "./js/count")
        .then((res) => {
            console.log("模块加载成功", res.default(2,1));
        })
        .catch((err) => {
            cosnole.log("模块加载失败", err);
        });
}

(2)Preload和Profetch技术

Preload:告诉浏览器立即加载资源

Prefetch:告诉浏览器在空闲时才开始加载资源

共同点:都只会加载资源,并不执行;都有缓存

区别:preload加载优先级高,prefetch加载优先级低;preload只能加载当前页面需要使用的的资源,prefetch可以加载当前页面资源,也可以加载下一个页面需要使用的资源。

总结:当前页面优先级高的资源用preload加载;下一个页面需要使用的资源用prefetch加载

问题:兼容性较差(preload相对于prefetch兼容性好一点) https://caniuse.com/查看兼容性

(3)Core-js:解决JS兼容性问题,专门用来做ES6及以上API的polyfill(补丁)

polyfill:用社区上提供的一段代码,让我们在不兼容某些新特性的浏览器上,使用该新特性。

javascript 复制代码
//babel.config.js
module.export = {
    //智能预设,能够编译ES6语法
    presets: [
        "@babel/preset-env",
        {
            useBuiltIns:"usage",// 按需加载自动引入
            corejs: 3,
        },
    ],
},

(4)PWA(progressive web application):渐进式网络应用程序

可以提供类似于native app(原生应用程序)体验的web app技术,在离线(offline)时应用程序能够继续运行功能,内部通过service workers技术实现的。

https://www.webpackjs.com/guides/progressive-web-application/#registering-our-service-worker

相关推荐
nppe64 分钟前
sequlize操作mysql小记
前端·后端
Moment13 分钟前
面试官:一个接口使用postman这些测试很快,但是页面加载很慢怎么回事 😤😤😤
前端·后端·面试
诗书画唱16 分钟前
【前端面试题】JavaScript 核心知识点解析(第二十二题到第六十一题)
开发语言·前端·javascript
excel23 分钟前
前端必备:从能力检测到 UA-CH,浏览器客户端检测的完整指南
前端
前端小巷子29 分钟前
Vue 3全面提速剖析
前端·vue.js·面试
悟空聊架构36 分钟前
我的网站被攻击了,被干掉了 120G 流量,还在持续攻击中...
java·前端·架构
CodeSheep38 分钟前
国内 IT 公司时薪排行榜。
前端·后端·程序员
尖椒土豆sss41 分钟前
踩坑vue项目中使用 iframe 嵌套子系统无法登录,不报错问题!
前端·vue.js
遗悲风42 分钟前
html二次作业
前端·html
江城开朗的豌豆1 小时前
React输入框优化:如何精准获取用户输入完成后的最终值?
前端·javascript·全栈