webpack配置

  1. webpack是构建在node.js基础之上的
  2. npm:node package manage(node包管理工具)
  3. 在终端输入pwd回车可以查看当前目录
  4. 可以在全局安装webpack,也可以在本地的工作目录下安装webpack,安装webpack需要安装两个包,一个是webpack主包,另一个是webpack-cli(表示我们可以在命令行里边执行webpack命令)
  5. 全局安装webpack:npm install webpack webpack-cli --global
    不推荐全局安装webpack,因为这样会使项目的webpack锁定到某个版本里,并且在使用不同的webpack版本的项目里边可能会导致构建失败,如果是一个团队协作的项目,你的小伙伴不知道是在全局里安装webpack,构建也会有问题,因此推荐在本地的工作目录下去安装webpack。
  6. 在安装本地的webpack之前,需要安装一个npm包管理的配置文件,执行一下npm init -y会在本地工作目录下产生一个package.json文件。
    工作目录安装webpack:npm init -y
    npm install webpack webpack-cli --save-dev
  7. 在项目的根目录下创建webpack.config.js文件,由于这个文件是在nodejs里面运行的,因此我们定义模块的时候得使用nodejs的CommonJs模块,使用module.exports来去定义,把他的值赋值为一个对象,这是一个配置对象
  8. webpack就像一条生产线,他要经过一系列的处理流程以后才能将源文件(我么称之为入口文件)转化成输出的结果,入口文件的js还可以依赖于其它的js,被依赖的js模块可能还依赖其它的js模块,并且这个js也可能会引用css文件,这个css文件的引入需要使用webpack loaders(加载器),webpack会把这个依赖的关系都记录下来,然后交给webpack编译器,webpack编译器经过加工以后会生成目标文件,比如css和js文件,webpack编译的过程需要应用一些工具来帮忙,这些工具可以帮助webpack来执行一些特定的任务,比如打包优化,资源管理等,这些工具就是我们所谓的plugins插件。
  9. 引入node的path模块可以用path.resolve(_dirname,'./src/js/index.js')获取以当前目录下文件的路径
    module.exports包含的一些比较常用的配置说明:
const HtmlWebpackPlugin = require('html-webpack-plugin')
// import HtmlWebpackPlugin from 'html-webpack-plugin'//与上面一行等价
const path = require('path') // path模块主要是为了解决绝对路径问题的,就是他要找的这个文件必须得有一个绝对路径,但你自己写的绝对路径肯定就很麻烦,所以我们可以使用path下面的resolve()方法
const MiniClassExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

module.exports = {
    mode: 'production', // webpack编译的模式:development, production
    entry: path.resolve(__dirname,'./src/js/index.js'), // 单页面,js文件的地址
    // entry:{ // 多页面
    //     index: path.resolve(__dirname,'./src/js/index.js'),// 点.代表根目录
    //     jquery: path.resolve(__dirname,'./src/js/jquery.js')
    // },
    // entry:{// 多页面,公共部分抽离出来
    //     index:{
    //         import: './src/js/index.js',
    //         dependOn: 'shared'
    //     },
    //     another: {
    //         import: './src/js/another.js',
    //         dependOn: 'shared'
    //     },
    //     shared: 'lodash' 
    // },
    output: {//输出,打包
        path: path.resolve(__dirname + '/dist'),//打包到哪个文件夹下,加+代表找一个文件夹
        filename: 'js/index.js',//哪个文件加下面的哪个js,dist文件夹下面的js文件夹下面的index.js文件//指定输出文件的文件名
        // filename:'[name].bundle'.js,//入口文件有多个时,为了避免输出文件名重复
        // publicPath:'./',//基本路径
        // outputDir:'dist',//输出文件目录
        clean:true,//清除没有用的dist文件
        assetModuleFilename:'images/test.png',// 资源模块的文件名或者路径
        // assetModuleFilename:'images/[contenthash][ext]',//contenthash:利用哈希值当文件名;ext:文件原本的扩展名
    },//输出,打包
    devtool:'inline-source-map',//生产环境不配置source map
    watch:true, //实现编译时自动监测文件变化的功能,需要手动刷新浏览器查看更改后的效果
    plugins:[ // 装的是实例化对象
        new HtmlWebpackPlugin({
            filename:'index.html',//打包后的filename是什么
            template:path.resolve(__dirname,'./src/index.html'),//打包的是谁
            chunks:['index'],
            // chunks:['jquery','index'],//入口文件是哪一个,可以写多个入口文件
            excludeChunks:['node_modules'] // 需要排除哪个文件
        }),
        new MiniClassExtractPlugin({
            filename: 'styles/[contenthash].css',// 打包的css放到styles文件夹下面(styles文件夹会自己创建)
        })
    ],
    module: {//配置规则
        rules: [{
            test: /\.png$/,
            type: 'asset/resource',//资源类型
            generator:{ //等价于上面的assetModuleFilename,generator的优先级比assetModuleFilename高
                // filename: 'images/test.png',
                filename: 'images/[contenthash][ext]',
            }
        },{
            // 在编译转换的时候要排除node-modules文件夹里面的js文件
            // package.json里面安装的那些依赖怎么用,设置规则
            test: /\.js$/,//匹配一个什么文件,后缀名以什么结尾的所有文件
            // loader: 'babel-loader',//要使用什么样的loader
            use:{
                loader: 'babel-loader',
                options: {
                    presets: ['@babel/preset-env'],//babel的预设
                    plugins:[[
                        '@babel/plugin-transform-runtime'
                    ]]
                }
            },
            exclude: /node_modules/
            // exclude: path.resolve(__dirname,'node_modules'),//这个规则排除哪些文件,不对哪些文件生效,例如node-module里面的不要打包
        },
        // {
        //     test: /\.css $/, 
        //     use: [
        //         'style.loader',
        //         'css-loader'
        //     ],//如果是多个loader就不能用loader了,用use,数组
        //     //webpack处理数组的时候是倒着处理的,从下往上处理:先处理css-loader,再处理style-loader(横着写的话是从右到左处理的)
        // },
        {
            test: /\.(css|sass)$/,
            use: [
                MiniClassExtractPlugin.loader,//把css放置到页面上
                'css-loader',//用于打包没有问题识别css文件
                'sass/loader'
            ]
        },{
            test: /\.tpl$/,
            loader:'ejs.loader'
        },{
            //加载字体资源
            test: /\.(woff|woff2|eot|ttf|otf)$/,
            type: 'asset/resource'
        }]
    }, 
    optimization:{//优化的配置
        minimizer:[//压缩代码的配置,还需要将mode得值改为production
            new CssMinimizerPlugin()
        ],
        splitChunks:{
            // 缓存组
            cachGroups:{
                vendor:{
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendors',
                    chunks: 'all'
                }
            }
        }
    },
    resolve:{
        alias: { 
            '@': path.resolve(__dirname,'./src')
        },
        extensions:['.json','.js','.vue'],//同名文件不同类型,先匹配json文件,再匹配js文件,再匹配vue文件
    },
    devServer:{//具有实时重新加载的功能,当我们的页面修改了,编译以后,浏览器会侦听到文件的修改来自动刷新(自动刷新浏览器展示更改后的效果)
        open:true,//当我在启动项目的时候自动打开浏览器
        host:'localhost',//主机
        port:'3300',//端口
        static:'./dist',//devServer指向的物理路径
        compress:'true',//增加一个压缩的头部
        historyApiFallback:true,// 找不到页面的时候跳转到首页
        hot:true,// 启动模块热更新
        headers:{
            'X-Access-Token':'abc123'
        }
    }
}

其实webpack-dev-server真正的没有输出任何的物理文件,他把输出的打包以后的文件放到了内存里,比如我们把打包生成的dist文件夹删除,再重新去浏览器访问,并不会发生任何问题,或者关闭服务,再重新启动服务,在浏览器里还是可以正常访问的,修改代码内容也会在浏览器里自动刷新,这样不但我们的开发效率提高了,连webpack的编译效率也同时提高了。

资源模块

  1. webpack最出色的功能之一就是除了可以引入js还可以是用内置的资源模块,使用asset modules来引入任何其它的类型资源,asset modules是一种模块类型,允许我们使用webpack来打包其它的资源文件(字体文件,图标文件等),资源模块的类型称为asset module type,会通过四种新的类型模块来替换所有的loader,这四种资源模块类型分别为:
  • asset/resource:会发送一个单独的文件并导出URL。
  • asset/inline:会导出一个资源的Data URL(比如可以把一个svg的图片转成一个base64的字符串,在代码里面可以直接引用这个字符串)。
  • asset/source:会导出资源的源代码。
  • asset:会在导出一个Data URL和发送一个单独的文件之间自动进行选择。(选择的依据事资源的大小,默认的资源大小事8kb,我们可以在定义资源类型的时候可以在parser对象下设置一个dataUrl condition这个属性,然后在这个属性下面设置一个MaxSize属性,就可以改变资源的默认大小了,资源小的时候选择 asset/inline类型,资源大的时候选择asset/resource类型)

loader

  1. 安装css的loader:npm install class-loader -D;npm install style-loader -D;npm install sass-loader -D
    D:安装在开发环境中
    webpack处理数组的时候是倒着处理的,从下往上,或者从右往左,所以css的loader要先解析css-loader,再解析style-loader,因为css-loader是用于识别css文件使打包没有问题,style-loader用于把css文件放置到页面的hear里
    webpack支持loader的链式调用,链式的每一个loader都可以对我们的源进行转换,而且转换是逆序的,第一个loader(css-loader)会将转换后的结果或者源代传递给下一个loader(style-loader),最后webpack希望最后一个loader返回一个js。
    sass-loader要放在最后,因为要用sass-loader去解析我们的css文件,然后再把解析好的文件交给css-loader,然后css-loader再把结果通过style-loader放置到页面的标签的head里。

抽离和压缩css

  1. 通过loader加载的css是跟html在一起的,如果想把style标签里的代码放置到一个单独的文件里,通过link标签去加载它,需要用到插件mini-css-extract-plugin:npm install mini-css-extract-plugin -D
    mini-css-extract-plugin是基于webpack5构建的,想使用的话必须在webpack5的环境下使用
    需要压缩css代码需要安装css-minimizer-webpack-plugin插件:npm install css-minimizer-webpack-plugin -D
  2. inner.HTML:识别html标签 W3C标准 保留空格和换行的;inner.Text: 不识别html标签 (非标准),去除空格和换行
小结:除了使用四种资源模块来引入外部资源以外,还可以使用loader来引入几大类型的文件,loader可以让webpack去处理其它类型的文件,并且将他们转化为有效的模块供应用程序使用

babel-loader

  1. balel-loader用于将ES6转换成低版本的浏览器能够识别的ES代码,需要安装三个包:
    npm install -D babel-loader @babel/core @babel/preset-env
  • babel-loader:在webpack里应用babel解析ES6的桥梁
  • @babel/core:babel的核心模块
  • @babel/preset-env:babel预设,一组babel插件的集合
    预设就是一组插件的集合,理论上我们每一个babel的解析都需要一个babel的插件,preset-env省的我们安装很多插件,她会把一组插件整合到一个文件里。(less-loader编译less文件,sass-loader编译sass文件,xml-loader编译xml文件,es6,es7文件等也需要编译)
  1. regeneratorRuntime是webpack打包生成的全局辅助函数,由babel生成,用于兼容async/await的语法,使用如下:npm install @babel/runtime -D;npm install @babel/plugin-transform-runtime -D
    @babel/plugin-transform-runtime这个插件会在需要regeneratorRuntime的地方自动require打包,然后编译的时候就会需要它。
小结:webpack天生可以自带加载js模块的功能,但是它只能做js模块化的打包,并不能转化js里的代码,比如将es6转化为es5,有时候我们的代码能正常运行,那纯靠浏览器解析,如果浏览器的版本比较低的话,运行的时候可能会发生错误,因此我们写代码的时候是需要babel来进行转化的,babel和webpack的结合就需要一个babel-loader。

代码分离

  1. 代码分离是webpack最引人注目的特性之一,这个特性能够把代码分离到不同的bundle中,所以bundle就是我们打包分离出来的文件,然后我们把这些文件按需加载,或者是并行加载,代码分离可以用于获取更小的bundle,以及控制资源加载的优先级,如果我们使用合理,会极大的影响加载时间,常用的代码分离方法有三种,分别是:
  • 配置入口起点:我们可以使用entry来配置手动的分离代码,这种方式有个问题,就是如果是多个入口,那么这些多个入口共享的文件会分别在每个包里边去重复打包(如果我们在入口的chunk之间包含一些重复的代码,那么这些重复的模块会被引入到各自得bundle中)。
  • 使用Entry dependencies或者SplitChunsPlugin去重和分离代码:防止重复打包。
  • 动态导入:通过模块的内联函数import调用来分离代码。

缓存

  1. 将第三方库(例如lodash)提取到单独的vendor chunk文件中,是比较推荐的做法,这是因为我们很少像本地的源代码那样频繁修改,因此通过以上步骤,利用浏览器的长效缓存机制,命中缓存来消除请求,并减少向server获取资源,同时还能保证浏览器代码和服务器代码版本一致,在optimization.splitChunks添加如下cacheGroups参数并构建。
    当我们的项目部署到服务器上的时候,浏览器加载完我们服务器上的文件,会缓存我们打包好的模块,如果我们修改了业务代码,文件名如果没有变,浏览器会使用用户本地缓存的内容,就获取不到新的内容了,因此我们得通过修改输出文件的文件名来解决这个问题,我们使用的是可替换模板字符串的方法来定义了contenthash,他能实现只要文件的内容不变哈希的字符串就不变;除了缓存业务代码,第三方的代码同样需要缓存,通过修改optimization.splitChunks这个属性来实现,我们可以定义一个cachGroups缓存组,将我们的业务代码引用的第三方的文件都打包到一个文件中,在浏览器中缓存,由于这类文件不频繁更新,所以我们可以提高首屏的打开速度节省网络流量。
    开发环境没有必要设置缓存,生产环境需要设置公共路径。

模块热更新

  1. 模块热替换“模块热替换功能会在应用程序运行过程中,替换、添加或删除模块,而无需重新加载整个页面,启用webpack的热模块替换特性,需要配置devServer.hot参数

webpack解析原理

  1. webpack通过Resolvers实现了模块之间的依赖和引用。所引用的模块可以是来自应用程序的代码,也可以是第三方库。resolver帮助webpack从每个require或者import语句中,找到需要引入到bundle中的模块代码,当打包模块时,webpack使用enhanced-resolve来解析文件路径。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容