webpack学习笔记

本文详细介绍了Webpack5的核心概念及使用方法,包括入口(entry)、输出(output)、加载器(loader)、插件(plugin)和模式(mode)等内容。此外,还探讨了如何处理CSS兼容性、压缩、语法检查等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

webpack是前端打包工具,目的是不需要开发者再去手动打包了,而是通过一系列配置,生成包。

好处是生成的代码运行高效,体积小,对浏览器有一定兼容性(需配置),混淆源码等。

缺点是对初学者这TM是啥?变秃也变强了?

 

对一个初学还健忘的人来说,还是多多记录一下来得实在。下面开始。

学习视频:尚硅谷2020最新版Webpack5实战教程(从入门到精通)

webpack五个核心概念:

  1. Entry:入口,指定webpack以哪个文件开始打包,分析构建内部依赖图。
  2. Output:输出,指定webpack打包后放哪,叫啥名。
  3. Loader:就是module,引用第三方模块让webpack能去处理非js文件,比如把less、ts转成浏览器能识别的css、js,图片转码,样式兼容等轻量级任务。
  4. Plugins:引入第三方插件让webpack执行更复杂的操作,比如压缩代码。
  5. Mode:分为development开发者模式、production生产者模式。

webpack4新增0CJS概念,即0配置,不再必需webpack.config.js,但默认入口为./src/index.js,出口./dist。

entry:

一般是单个js文件,也可以是多个。

entry:{
    home: '.src/home.js',
    about: '.src/about.js',
    other: '.src/other.js',
}

output:

包含属性filename(标识输出js文件名称),path(输出的位置,最好用绝对路径)

const { resolve } = require('path')

module.exports = {
    output:{
        filename: 'build.js',
        path: resolve(__dirname, 'build')
    }
}

loader:

需要注意在文件中根属性是module,且引用的loader是自下而上,自右向左顺序执行的。

举个例子: 

use: ['style-loader', 'css-loader', 'less-loader'],

//或
//use: [
//    'style-loader', 
//    'css-loader', 
//    'less-loader'
//],

执行顺序是less-loader,css-loader,style-loader。

 

下面开始列举几个基础loader

1.  css-loader

打包css文件用的,目的是将css文件变成commonjs加载到js中,内容是样式字符串,注意是.css文件中的样式

2.  style-loader一般是配合css-loader使用,目的是创建style标签,将js中的样式资源添加到header中,注意是js中的样式

打包css文件用法:

module:{
    rules:[
        {
            test: /\.css$/,
            use: ['style-loader','css-loader']
        }
    ]
}

3.  less-loader

将less样式转化为css样式,sass-loader同理。

打包less文件用法:

module:{
    rules:[
        {
            test: /\.less$/,
            use: ['style-loader','css-loader','less-loader']
        }
    ]
}

4.  url-loader

打包样式中引用的图片资源,需要依赖file-loader,还可以对图片文件进行压缩(转base64码),可通过limit、name属性设置压缩范围和压缩文件名。

打包图片用法:

module:{
    rules:[
        {
            test: /\.(png|jpe?g|gif)$/,
            loader: 'url-loader', // 当只引用一个依赖时可用loader
            options:{
                limit: 8*1024, // 8kb以下文件会转base64存放到js中,适用于小文件,减少文件数量,提高效率。
                name: '[hash:10].[ext]', // 对压缩后的文件重命名,默认生成32位hash值名称,设置截取10位,ext表示原文件扩展名
                // outputPath: '' // 可以指定output文件夹下的文件层级
            }
        }
    ]
}

5.  html-loader

打包html中引用的图片资源,但需要额外注意,url-loader是用ES6 module去解析,而html-loader是通过commonjs去引入的,所以会冲突报错,需要将url-loader中的ES6 module关闭,统一成commonjs。

用法:

module:{
    rules:[
        {
            test: /\.(png|jpe?g|gif)$/,
            loader: 'url-loader', // 当只引用一个依赖时可用loader
            options:{
                limit: 8*1024, // 8kb以下文件会转base64存放到js中,适用于小文件,减少文件数量,提高效率。
                name: '[hash:10].[ext]', // 对压缩后的文件重命名,默认生成32位hash值名称,设置截取10位,ext表示原文件扩展名
                esModule: false,
            }
        },
        {
            test: /\.html$/,
            loader: 'html-loader', // 当只引用一个依赖时可用loader
        }
    ]
}

6.  file-loader

一般用于上面文件外的其他文件打包

用法:

module:{
    rules:[
        {
            exclude: /\.(html|css|less|png|jpe?g|gif)$/,
            loader: 'file-loader', // 当只引用一个依赖时可用loader
            options:{
                name: '[hash:10].[ext]'
            }
        }
    ]
}

 

plugins:

需要先用nodejs方式引入插件包,才能使用(loader只需要安装依赖,不需要引入)

下面开始列举几个基础plugins

1.  htmlwebpackplugin

打包html主页面的

用法:

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

module.exports = {
    plugins:[
        new HtmlWebpackPlugin({
            template: './public/index.html'
        })
    ]
}

2.  DefinePlugin

相当于在webpack中定义一些全局变量,这样在打包时,都会动态读取这些变量,方便维护。

用法:

// webpack.config.js
const webpack = require('webpack')

module.exports = {
    plugins:[
        new webpack.DefinePlugin({
            MY_URL: 'www.baidu.com' // 自定义
        })
    ]
}


//业务文件中
console.log(MY_URL) // 直接使用

3.  MiniCssExtractPlugin

按上面loader对css的打包,可以知道我们把css合到js中了,如果想分离出来,需要用到此插件。需要注意的是,如果使用此插件,对css的loader解析需要相应修改,用此插件的loader代替style-loader。

用法:

const MiniCssExtractPlugin = require('mini-css-extract-plugin)
module:{
    rules:[
        {
            test: /\.css$/,
            use: [
                // 'style-loader',
                MiniCssExtractPlugin.loader, // 用自带loader代替style-loader,这样会独立成一个css文件,而不是加载到header中
                'css-loader'
            ]
        }
    ],
    plugins:[
        new MiniCssExtractPlugin({
            filename: 'build.css' // 可重命名,默认main.css
        })
    ]
}

 

其他属性:

1.devServer

开发服务器,主要用于开发模式,通过配置devServer可自动编译、自动打开默认浏览器、自动刷新页面。只会在内存中打包,不会有任何输出。运行指令为 npm 

用法:

const { resolve } = require('path')

module.exports = {
    devServer: {
        contentBase: resolve(__dirname, 'build'), // 选择编译后的目录,而不是原代码
        compress: true, // 启动gzip压缩
        port: 8090, // 服务的端口号
        open: false, // 设置true后,每次运行自动打开默认浏览器
    }
}

 

 

css兼容性处理

需要用到postcss里面的postcss-loader和postcss-preset-env,其中postcss-preset-env用来帮助postcss-loader找到package.json下的browserslist配置。默认情况下,browserslist读的是生产环境下的配置,而且它不是读的webpack.config下的mode,而是读的node中的环境变量,如果需要设置,需在webpack.config module.exports前,设置process.env.NODE_ENV = 'development'

用法:

// webpack.config.js
module:{
    rules:[
        {
            test: /\.css$/,
            use: [
                'style-loader',
                'css-loader',
                {
                    loader: 'postcss-loader',
                    options:{
                        ident: 'postcss',
                        plugins: ()=>{
                            require('postcss-preset-env')()
                        }
                    }
                }
            ]
        }
    ]
}


//package.json

{
    "browserslist": {
        "development":[
            "last chrome 1 versions", // 兼容chrome上一个版本
            "last firefox 1 versions",
            "last safari 1 versions",
        ],
        "production":[
            "> 0.2%", // 兼容99.8%的浏览器
            "not dead", // 不要已经死掉的浏览器
            "not op_mini all" // 不要op_mini浏览器?
        ]
    }
}

//{
//    "browserslist": [
//        "> 1%", // 兼容99%的浏览器
//        "last 2 versions", // 兼容上2个版本
//        "not dead"
//    ]
//}

 

css压缩

OptimizeCssAssetsWebpackPlugin

用法:

const OtimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')

module.exports = {
    plugins:[
        new OtimizeCssAssetsWebpackPlugin()
    ]
}

 

JS语法检查

团队协作中,统一各开发者使用规范,需要用到eslint-loader,具体的参考下面的随笔吧。

webpack---eslint-loader学习随笔

如果要检查打包后并自动修复的话,在options中设置fix:true。enforce: 'pre',设置优先执行。

eslint-loader要优先于babe-loader

 

JS兼容

使用babel-loader,需要用到@babel/core @babel/preset-env,分为三种方式:

1.@babel/preset-env只能处理基本js兼容,promise等不能转换

2.@babel/polyfill做全部兼容性处理,是将所有兼容性代码全部引入,体积较大

3.core-js按需加载

用法:

modules:{
    rules:[
        {
            test:/\.js$/,
            exclude:/node_modules/,
            loader: 'babel-loader',
            options: {
                // 预设babel做怎样的兼容处理
                presets: [
                    [
                        '@babel/preset-env',
                        {
                            //按需加载
                            useBuiltIns: 'usage',
                            // 指定下载的core-js版本
                            corejs:{
                                version: 3
                            },
                            //指定兼容性做到哪个版本浏览器
                            targets:{
                                chrome: '60',
                                firefox: '60',
                                ie: '9',
                                safari: '10',
                                edge: '17',
                            }
                        }
                    ]
                ]
            }
        }
    ]
}

 

html压缩

在htmlwebpackplugin中移除空格和移除注释

用法:

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

module.exports = {
    plugins:[
        new HtmlWebpackPlugin({
            template: './public/index.html',
            minify:{
                collapseWhitespace: true, //移除空格
                removeComments: true, // 移除注释
                removeAttributeQuotes: true // 移除双引号
            }
        })
    ]
}

 

source-map

一种提供源代码到构建后代码映射的技术,用于开发环境下调试代码。一句话就是调试的时候能追踪到代码出错的位置并提示。

支持多种形式: [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map,且可以组合

打包后的文件,根据形式不同,会在打包代码内联或外部生成映射代码,内联构建速度更快。

source-map:外部,提示错误代码准确信息和源代码错误位置

inline-source-map:内联,只生成一个内联source-map,提示错误代码准确信息和源代码错误位置

hidden-source-map:外部,提示错误代码准确信息,不能提示源代码错误位置,只能提示构建后代码错误位置

eval-source-map:内联,每个文件后都生成对应source-map,提示错误代码准确信息和源代码错误位置,位置带hash文件名

nosources-source-map:外部,提示错误代码准确信息,但没有任何原代码信息

cheap-source-map:外部,提示错误代码准确信息和源代码错误位置,但只能精确到行,若多个代码在一行,没法具体到哪一块代码

cheap-module-source-map:外部,同cheap,module会将loader的source-map也加进来

在开发环境下,要求速度快,方便调试

速度快(eval>inline>cheap>...),最优:

  eval-cheap-source-map

  eval-source-map

方便调试,最优:

  source-map

  cheap-modules-source-map

  cheap-source-map

生产环境下,代码要不要隐藏?调试是否友好?由于内联会使包体积增大,因此推荐外部

要隐藏的话,选hidden-source-map(只隐藏源码,会提示错误信息) / nosources-source-map(全部隐藏)

调试:source-map / cheap-module-source-map

 

oneOf

用于loader-rules中,表示对oneOf下的loader,只匹配其中一个,相当于else if,如果走其中一个,其他就不用走了

假设css文件,只需要走css的处理loader,不需要走less、sass、js等loader。

用法:

modules:{
    rules:[
        // 在rules下的,默认每来一个文件都会去匹配
        {
            test:/\.js$/,
            ...
        },
        // 以下loader只会匹配一个,不能有两个loader处理同一类型文件
        {
            oneOf: [
                {
                    test:/\.css$/
                    ...
                },
                {
                    test:/\.js$/
                    ...
                }
            ]
        }
    ]
}

//相当于
if(){}
if(){}else if(){} else if(){}

 

缓存

缓存包括对js编译的缓存和对项目资源的缓存。

生产环境下,对babel进行缓存,由于babel会对js代码编译,若只修改其中一个,无需重新编译其他js,直接读缓存即可。

用法:

modules:{
    rules:[
        {
            test:/\.js$/,
            exclude:/node_modules/,
            loader: 'babel-loader',
            options: {
                // 预设babel做怎样的兼容处理
                presets: [
                    ...
                ],
                // 开启babel缓存,第二次构建时会读取之前缓存
                cacheDirectory: true
            }
        }
    ]
}

项目资源即打包后的文件,给文件名拼接一个唯一值,可避免浏览器因缓存不请求构建代码的问题,分为hash、chunkhash、contenthash

一种是添加hash,有个缺点:css、js共用一个hash值,当重新打包时,导致所有缓存失效,但我可能只修改了其中一个文件

如:

module.exports = {
    output:{
        filename: 'build.[hash:10].js'
        ...
    },
    plugins: [
        new MiniCssWebpackPlugin({
            filename: 'css/built.[hash:10].css'
        })
    ]
}

另一种是chunkhash,根据chunk生成的hash值,如果打包来源于同一个chunk,那么hash值一样。chunk指代码块,当一个index.js作为入口,引用了其他文件时,这些文件都属于一个chunk。代码参考上图,hash换成chunkhash。

最后一种是contenthash,根据文件内容生成hash值,不同文件的hash值不一样。代码参考上图,hash换成contenthash。使用contenthash最佳。

 

tree shaking

webpack内置的优化,去除无用代码

前提:1.必须使用ES6模块化      2.开启production模式

使用过程中可能会有问题:可能会无意间将css等代码当无用代码去除掉。

需要在package.json中设置"sideEffects":["*.css"] 等,保证css等文件不会被tree shaking。

 

code split

代码分割,可以采取多入口方式,配置optimization,或动态导入的方式,打包出多个js文件。

optimization用法:

//webpack.config.js
module.exports = {
    //可以将node_modules中代码单独打包成一个chunk
    //自动分析多入口chunk中,是否包含公共文件,如果有会打包成单独一个chunk
    optimization: {
        splitChunks: {
            chunks: 'all'
        }
    }
}

动态导入用法

//业务模块
//webpackChunkName 固定名字
import(/* webpackChunkName: 'test' */'./test')
    .then(({add}) => {
        add(2, 3)
    })
    .catch(() => {})


//test.js
export function add(a, b) {
    return a+b
}

 

懒加载

使用代码分割的思路,前提是代码块放在回调函数中,不会立即执行,且要懒加载的代码块被分割出来了。

用法:

//绑定的某事件回调中
//webpackChunkName 固定名字
//webpackPrefetch 预加载:页面运行会先加载js文件,用的时候读缓存,真正执行js文件
//正常加载是顺序加载,预加载是等其他加载完毕,浏览器空闲时再加载
import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test')
    .then(({add}) => {
        add(2, 3)
    })
    .catch(() => {})


//test.js
export function add(a, b) {
    return a+b
}

 

PWA

渐进式网络开发应用程序,让网页离线也可以访问(前提是先进入页面,再离线,页面不会跳404)。要求service-worker.js代码必须运行在服务器上

用法:

//webpack.config.js
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
module.exports = {
    plugins:[
        new WorkboxWebpackPlugin .GenerateSW({
            clientsClaim: true,
            skipWaiting: true
        })
    ]
}


//js主入口
//注册serviceworker
//处理兼容性问题
if('serviceWorker' in navigator){
    window.addEventListener('load',() => {
        navigator.serviceWorker.register('./service.worker.js') // service.worker.js是打包会自动生成的文件
            .then(() => {
                console.log('')
            })
            .catch(() => {
                console.log('')
            })
    })
}


//package.json
//通常eslint不识别window、navigator等浏览器对象,需要设置
"eslintConfig":{
    "env":{
        "browser": true,//支持浏览器端全局变量
        //"node": true,//支持nodejs全局变量
    }
}

 

多线程

thread-loader

用法:

module:{
    rules:[
        {
            test: /\.js$/,
            use:[
                {
                    loader: 'thread-loader',
                    options: {
                        workers: 2 //线程数
                    },
                },
                {
                    loader: ...
                }
            ]
        }
    ]
}

 

externals

对一些选择从cdn加载的资源禁止本地打包,

用法:

module.exports = {
    externals:{
        jquery: 'jQuery'
    }
}

 

dll

使用dll技术,对某些(第三方)库进行单独打包

对jquery打dll包用法:

//webpack.dll.js
const {resolve} = require('path)
const webpack = require('webpack')
module.exports = {
    entry: {
        jquery: ['jquery'] //要打包的库是jquery
    },
    output: {
        filename: '[name].js',
        path: resolve(__dirname, 'dll'),
        library: '[name]_[hash]' //打包的库里面向外暴露出去的内容叫什么
    },
    plugins: [
        // 打包生成一个manifest.json 提供和jquert映射关系,告诉webpack不需要再打jquery了
        new webpack.DllPlugin({
            name: '[name]_[hash]', // 映射库的暴露的内容名称
            path: resolve(__dirname, 'dll/manifest.json') // 输出文件路径
        })
    ]
}

运行  webpack --config webpack.dll.js

对项目打包时:

//webpack.config.js
const {resolve} = require('path)
const webpack = require('webpack')
const AddAssetHtmlWebpackPlugin= require('add-asset-html-webpack-plugin')
module.exports = {
    entry: './src/index/js',
    output: {
        filename: 'built.js',
        path: resolve(__dirname, 'build')
    },
    plugins: [
         // 告诉webpack哪些库不参与打包,同时使用时名称也得变
        new webpack.DllReferencePlugin({
            manifest: resolve(__dirname, 'dll/manifest.json')
        }),
        // 将某个文件打包输出去,并在html中自动引入该资源
        new AddAssetHtmlWebpackPlugin({
            filepath: resolve(__dirname, 'dll/jquery.js')
        })
    ]
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值