webpack 详解

/**
 * HMR: hot module replacement 热模块替换./ 模块热替换
 * 需在devServer 添加hot属性
 * 作用:一个模块发生变化,只会重新打包这一个模块,(而不是打包所有模块)
 *      极大提升构建速度
 *      样式文件:可以使用HMR 功能 :因为style-loader内部实现了
 *      js文件: 默认不能使用HMR 功能   ==》 需要修改js 代码,添加支持HMR功能的代码
 *           注意:HMR  只能对js的处理,只能处理非入口文件js的其它文件
 *      html文件:默认不能使用HMR 功能,同时会导致问题:html 不能热更新了 (不需要做HMR功能)
 *          解决:修改entry 入口 为数组, 将html 文件引入
 * 
 */


 /**
  * webpack 优化如下:
  * 
  * 1.缓存:
  *  babel 缓存
  *  cacheDirectory:true
  *  ---> 让第二次打包构建速度更快
  *  文件资源缓存
  *     hash:每次webpack构建时会程程一个唯一的hash的值
  *     问题:因为js和css 同时使用一个hash值
  *         如果重新打包,会导致所有缓存失效,(可我缺只改动了一个文件)
  *     chunkhash:根据chunk生成的hash值,如果打包来源于同一个chunk,那么hash值就一样
  *     问题:js和css 的hash值还是一样的
  *         因为css 是js中被引入的 所以同属于一个hash值
  *     contenthash:根据文件内容生成hash值,不同文件的hash值不一样
  *      ---> 让代码上线运行缓存更好使用
  * 
  * 2.tree shaking (树摇) 去除无用代码
  *     前提:1.必须使用es6模块化,2.开启production环境
  *     作用:减少打包体积
  *     注:
  *     在package.json 中配置
  *         'slideEffects':false, 所有代码都没有副作用,(都可以进行tree shaking)
  *             问题:可能回把css/@babel/polyfill (副作用)文件干掉
  *              改成'slideEffects':["*.css",'*.less'],
  * 3.代码分割
  *     
  */
// node 中的变量
const {resolve}=require('path')
//拆分css 插件
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
//对CSS代码进行压缩
const OptimizeCssAsetsWebpackPlugin=require('optimize-css-asets-webpack-plugin')
//引入html模板插件=>对html 处理
const HtmlWebpackPlugin=require('html-webpack-plugin')
//定义node.js 环境变量:决定使用browserslist的那个环境
process.env.NODE_ENV='production'

// 复用loader
const commonLoader=[
// 'style-loader',
    // 这个loader 取代style-loader,作用:提取js中的css成单独文件
    MiniCssExtractPlugin.loader,
    'css-loader',
        /** 对样式兼容性处理 */
        {
        //还需要在package.json 中定义browserslist兼容哪些浏览器
        loader:'postcss-loader',       //该loader 只能解析css 文件
        options: {
             postcssOptions:{
                 plugins: [[postcss-preset-env,{}]]
                 }
        }

    },
]
/**
 * loader: 1. 下载 2. 使用(配置loader)
 * pulgin:1. 下载 2. 引入 3. 使用
 */

module.exports={
    //入口文件
    // html文件:默认不能使用HMR 功能,同时会导致问题:html 不能热更新了 (不需要做HMR功能)
    // *          解决:修改entry 入口 为数组, 将html 文件引入
    // entry:['./src/js/index.js','./src/index.html'],
    entry:'./src/js/index.js',
    //输出对象
    output:{
        //输出文件名
        filname:'js/build.js',
        //输出文件目录,_dirname nodejs 的变量 代表当前文件的目录的绝对路径
        path:resolve(__dirname,'build')
    },
    //loader加载器 =》翻译官
    module:{
        rules:[
            //一下loader只会匹配一个
            // 注意不能有两个配置处理同一种类型文件
            // 优化:提高构建速度
            // oneOf:[]
            {
                test:'/\.css$/',
                // 使用多个loader 的时候 使用use  只有一个时候 就用laoder
                use:[ //改数组的执行顺序是 从下往上执行
                    // // 'style-loader',
                    // // 这个loader 取代style-loader,作用:提取js中的css成单独文件
                    // MiniCssExtractPlugin.loader,
                    // 'css-loader',
                    // /** 对样式兼容性处理 */
                    // {
                    //     //还需要在package.json 中定义兼容哪些浏览器
                    //     loader:'postcss-loader',    //该loader 只能解析css 文件
                    //     options: {
                    //          postcssOptions:{
                    //              plugins: [[postcss-preset-env,{}]]
                    //              }
                    //     }
                    // }
                    ...commonLoader
                ]
            },
            {
            /***
             * 
             * 注义: use:数组的执行顺序是 从下往上执行先执行less-loader 会将less 文件编译成css文件,经过postcss文件时
             * 会将css文件做兼容性处理,再通过css-loader加载到js 中,再由minicssextractplugin插件从js中提取出来成为单独文件
             * 
             */
                test:'/\.css$/',
                use:[ //改数组的执行顺序是 从下往上执行
                    // 'style-loader',
                    // 这个loader 取代style-loader,作用:提取js中的css成单独文件
                    // MiniCssExtractPlugin.loader,
                    // 'css-loader',
                    //  /** 对样式兼容性处理 */
                    //  {
                    //     //还需要在package.json 中定义browserslist兼容哪些浏览器
                    //     loader:'postcss-loader',       //该loader 只能解析css 文件
                    //     options: {
                    //          postcssOptions:{
                    //              plugins: [[postcss-preset-env,{}]]
                    //              }
                    //     }
                    // },
                    
                    ...commonLoader,   //取上面的定义的变量
                    'less-loader'
                ]
            },
            /**
             *  正常来讲,一个文件只能被一个loader处理
             * 当一个文件被多个loader处理,那么一定要指定老弟儿执行的先后顺序:
             * 先执行eslint 在执行babel,需要设置 enforce参数
             * 
             */
            {
                /**
                 * 语法检查: eslint-loader  eslint
                 * 注意:只检查自己写的源码,第三方的库是不会检查的
                 * 设置检查规则:
                 *  package.json中eslintConfig中设置~
                 *    eslintConfig:{
                 *          'extends':'airbnb-base'
                 *      }
                 *  aribnb --> eslint-config-airbnb-base eslint-plugin-import  eslint
                 */
                test:/\.js$/,
                //排除文件
                exclude:/node_modules/,
                //执行顺序=>优先执行 在所有loader中 优先执行
                enforce:'pre',
                loader:'eslint-loader',
                options:{
                    //自动修复 eslint 的错误
                    fix:true,   
                },
            },
            {
                /**js 兼容性处理:babel-loader @babel-core 
                 * 1. 基本js兼容处理 --> @babel/preset-env
                 *  问 :只能转换基本语法,列如:箭头函数,再如:promise高级语法就不能转换
                 * 2.全部js兼容性处理  --> @babel-polyfill
                 *   直接在全局中 引入 import '@babel-polyfill'
                 *  问题:只需要解决部分兼容性问题,但是会将所有的兼容代码引入 ,体积太大
                 * 3.需要做兼容性处理的就做:按需加载 --> core-js
                  */
                test:/\.js$/,
                //排除文件
                exclude:/node_modules/,
                loader:'babel-loader',
                options:{
                    //y预设:指示babel做怎么样的兼容性处理
                   persets:[
                       '@babel/perset-env',
                   /**以下 方式 则 是第三种方案 => 按需加载 */
                    {
                        //按需加载
                        useBulitIns:'usage',
                        //指定core-js版本
                        corejs:{
                            version:3
                        },
                        //指定兼容性做到哪个版本浏览器
                        targets:{
                            chrome:'60',
                            firefox:'60',
                            ie:'9',
                            safari:'10',
                            edge:'17'    
                        }
                    }
                    ],
                    // 开启babel 缓存
                    // 第二次构建时,会读取之前的缓存
                    cacheDirectory:true,
                },
            },
            {
                // 问题:默认处理不了html中的img 图片资源
                test:/\.(jpg|png|gif)/,
                loader:'url-loader',
                options:{ //该字段为重新定义
                    limit:8*1024,   // 小于8kb的文件进行base64处理, 优点:减少请求数量(减轻服务器压力),缺点:图片体积会更大 文件请求速度更慢
                    name:'[hash:10].[ext]',   //给图片重命名,[hash:10]取图片的hash的前10位,[ext]取文件原来的扩展名
                    outputPath:'imgs',   //s输出文件
                    //问题 因为url—loader 默认使用es6模块化解析,而html-loader引入图片时commonjs
                    //解析是出现问题:[object module]
                    //解决: 关闭url-loader 的es6模块化,使用commonjs 解析
                    esModule:false, //关掉es6   //如果是webpack 是5 的 esModule:false,放到html-loader那里就可以了
                }
            },
            {
                /** 为了专门处理html中的图片问题 (负责引入img , 从而被url-loader处理) */
                test:/\.html*$/,
                loader:'html-loader',   // 此loader 使用的模板化是commonjs  而url loader 使用的是es6
                // options: {
                //      esModule:false, //关掉es6   //如果是webpack 是5 需要此操作
                // }
            },
            {
                /** 其他文件处理 */
                exclude:/\.(js|css|less|html|jpg|png|gif)/,
                loader:'file-loader',
                options:{
                    outputPath:'media'   //s输出文件
                }
            },
        ]
    },
    
    plugins:{
        
        //功能:拆分css 代码成一个单独文件
        new MiniCssExtractPlugin({
            //重命名目录
            filname:'css/build.css',
        }),
        //功能:压缩css 代码
        new OptimizeCssAsetsWebpackPlugin(),
        //功能:默认会创建一个空的 html ,自动引入打包输出的所有资源(js/css)
        new HtmlWebpackPlugin({
            template:'./src/index.html', // 以指定html文件为模板创建新的html文件
            //压缩html代码
            monify:{
                //移除空格
                collapseWithspace:true,
                //移除注释
                removeComments:true,
            }
        }),
    },
    //解析模块的规则
    resolve:{
        //配置解析模块路径别名:优点点简写路径,缺点路径没有提示
        alias:{
            $css:resolve(__dirname,'src/css')
        },
        //配置省略文件路径的后缀名
        extensions:['.js','.json','.css'],
        //告诉webpack 解析模块是去找哪个目录
        moudules:[ resolve(__dirname,'../../node_modules'),'node_modules']
    },

    /**
     *  1.可以将node_modules 中代码单独打包一个chunk最终输出
     *  2. 自动分析多入口chunk中,有没有公共的文件,如果有会打包成单一的chunk
     * */
    optimization:{
        splitChunks:{
            chunks:'all',
            //以下模块不写不配置就会使用其默认值
            // minSize:30*1024 ,   //分割的chunk 最小为30kb
            // maxSize:0,  //最大没有限制
            // minChunks:1,// 要提取的chunk最少被引用1次
            // maxAsyncRequests:5 ,// 按需加载时并行加载的文件的最大数量
            // maxInitialReaquwsts:3 ,// 入口js文件最大请求数量
            // automaticNameDelimiter:'~' ,// 名称链接符
            // name:true,  //可以使用命名规则
            // cacheGroups:{    //分割chunk的组
            //     //node_modules 文件会被打包到vendors组的chunk中 ==》vendors~xxx.js
            //     //满足上面的规则,如:大小超过30kb,至少被引用一次
            //     vendors:{
            //         test:'/[\\/]node_modules[\\/]/',
            //         //优先级
            //         priority:-10,
            //     },
            //     default:{
            //         // 要提取chunk至少被引用2次
            //         minChunks:2,
            //         //优先级
            //         priority:-20,
            //         //如果是当前要导报的模块,和之前已经被提取的模块是同一个,就会复用,而不是重新打包模块
            //         reuseExistingChunk:true,
            //     }
            // }
        }
    },
    //生产环境下 webpack会自动压缩js代码 mode:'production'
    mode:'development',
    // 开发模式
    devServer:{
        //运行代码的目录
        contentBase:resolve(__dirname,'build'),
        //坚实contentBase目录下的所有文件,一旦文件变化就会reload
        watchContentBase:true,
        watchOptions:{
            //忽略文件
            ignored:/node_modules/
        },
        // 启动gzip压缩
        compress:true,
        // z指定端口号
        port:3000,    // 启动端口
        host:'localhost',//域名
        open:true,  //是否默认打开浏览器
        hot:true,  // 开启HMR功能=> 热更新 
        clientLogLevel:'none',//b不显示启动服务器日志信息
        quiet:true,// 除了一些基本启动信息以外,其他内容都不要显示
        //如果出错了不要进行全屏提示
        overlay:false,
        // 服务器代理===》  解决开发环境跨域问题
        proxy:{
            //一旦devServer(5000) 服务器接收到/api/xxx 开头的请求,就会把请求转发到另一个服务器
            '/api':{
                target:'http://localhost:3000',
                // 发送请求是,请求路径重写:讲/api/xxx ===>/xxx(去掉/api)
                pathRewrite:{
                    '^/api':''
                }
            }
        }
    },
    /**
     * source-map: 一种提供源代码到构建后代吗映射 技术,(如果收件后代码出错了 通过映射可以追踪源代码错误)
     * 
     * [inline-|hidden-|eval-][nosource-][cheap-[module-]] source-map
     * source-map: 外部
     *  1.错误代码准确信息和源代码的错误位置
     * inline-source-map:内联
     *  1.只生成一个内联source-map1
     *  2.错误代码准确信息和源代码的错误位置
     * hidden-source-map:外部
     *  1.错误代码,错误原因,没有错误位置
     *  2.不能跟踪准确信息,和错误位置
     * eval-source-map:内联
     *  1.每个文件都会生成一个source-map eval
     *  2.错误代码准确信息和源代码的错误位置
     * nosource-source-map:外部
     *  1.能找错误的准确信息,但是没有任何源代码信息
     * cheap-source-map:外部 
     *  1.错误代码准确信息和源代码的错误位置,只能精确到行
     * cheap-module-source-map:外部
     *  1.错误代码准确信息和源代码的错误位置,只能精确到行
     * 
     * 
     * 内联和外联的区别:1.外部生成了文件,内联没有,2.内联构建速度更快
     * 
     * 开发环境:速度快,调试更友好
     *  1.速度快 eval>inline>cheap>eval-cheap-source-map>eval-source-map
     *  2.调试更友好
     *      source-map>eval-cheap-source-map>cheap-source-map
     * 
     *  结论:==》 eval-source-map/eval-cheap-moudle-souce-map 
     * 
     * 
     * 生成环境:源代码要不要隐藏?调试要不要达到更友好
     * 内联:体积大,所以生产环境不用内联
     * source-map
     */
    devtool:'source-map'

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值