webpack学习记录

webpack

webpack核心概念

​ webpack 静态模块打包器,是一种前端资源构建工具,前端所有资源文件(js/json/img/less…)都会作为模块处理,它将根据依赖关系进行静态分析,打包生成对应的静态资源(bundle)。

一、Entry

​ 入口(Entry)指示webpack以哪个文件为入口起点开始打包分析构建内部依赖图。

二、Output

​ 输出(Output)指示webpack打包后的资源bundles输出到哪里去,以及如何命名。

三、Loader

​ Loader让webpack能够处理那些非JavaScript文件(webpack自身只理解JavaScript)

Loader去翻译这些css,img等

四、Plugins

​ 插件(Plugins)可以用于执行范围更广的任务。插件范围包括,从打包优化和压缩一直到重新定义环境中的变量等。

五、Mode

​ 模式指示webpack使用相应的模式配置

​ development:会将process.env.NODE_ENV的值设置为development,并启用一些插件。能让代码在本地调试及运行。

​ production:会将process.env.NODE_ENV的值设置为production,并启用一些插件。能让代码优化上线的运行的环境。

开发环境:webpack ./src/index.js -o 输出到 ./build/built.js(可自己配置) --mode=development

webpack会以 ./src/index.js为入口文件开始打包,打包后输出到 ./build/built.js

整体打包环境,是开发环境

生产环境:webpack ./src/index.js -o 输出到 ./build/built.js(可自己配置) --mode=production

webpack:会以 ./src/index.js为入口文件开始打包,打包后输出到 ./build/built.js

整体打包环境,是生产环境

结论:

​ 1,webpack能处理js/json资源,不能处理css/img 等其他资源

​ 2,生产环境比开发环境对一个压缩js代码

3。生产环境和开发环境将Es6模块化编译成浏览器能够识别的模块化

可以吧打包后的./build/built.js 引入到index.html 进行验证

webpack 详细配置

/*

webpack.config.js 是webpack的配置文件
作用就是指示webpack干哪些活(运行webpack时,会运行其中的配置)

HMR的作用:hot module  replacement  模块热替换. 作用:一个模块发生变化,只会重新打包发生过变化的模块。
js,没有HMR ,需要修改js代码,添加支持HMR的代码
在index.js中
if(module.hot) {
    // 一旦module.hot 为true 说明开启了HMR功能 --> 让HMR代码生效
    // 如果有其他模块也需要开启HMR ,就再写一个module.hot.accept() 
    module.hot.accept('xxx.js',function(){
        // 方法会监听print.js文件的变化,一旦发生变化,其他模块会重新打包构建
        // 会执行后面的回调函数
    })
}
HTML文件没有HMR,并且会导致重新编写html不会重新更新
解决: 修改entry 入口,将html 引入


所有的构建工具都是基于node平台运行的,模块化默认采用common.js
loader 先下载 再使用(及配置loader)
plugins: 先下载 再引入  再使用


运行指令:webpack   会将打包的文件输出
npx wenpack-dev-server  // 不会输出打包文件


source-map: 一种提供源代码到构建后代码映射技术(如果构建后代码出错了,通过映射可以追踪到源代码错误)
只需要加一句: devtool: 'source-map' 能够准确定位到源代码错误的位置
devtool: inline-source-map 内联(只生成一个内联的source-map) 内联会让体积变大,一般不使用
devtool: hidden-source-map 外部生成   定位到构建后代码的错误位置,是为了隐藏源代码,一般在生产环境下使用
devtool: eval-source-map 内联(每一个js文件生成一个source-map)
devtool: nosources-source-map 外部生成   找不到源代码错误,找不到错误位置,是为了隐藏源代码,一般在生产环境下使用
devtool: cheap-source-map 外部生成  只精确到行的错误位置,不推荐使用
devtool: cheap-module-source-map 外部生成 能够准确定位到源代码错误的位置
使用时考虑环境: 开发环境:速度快,调试更友好
速度: eval>inline>cheap..
eval-cheap-source-map 组合最快
调试更友好 : cheap-module-source-map 
--> 综上选择 eval-source-map /
生成环境:源代码要不要隐藏?调试要不要友好
一般使用--> source-map  /cheap-moudle-source-map


缓存:
babel 缓存 -- 直接配置即可  --> 第二次打包更快
文件资源缓存-- 给文件名添加hash值,每次webpack构建时会生成一个唯一的hash值,只要文件没变hash值就不会变
为什么要这样配置:因为后端如果做了强制缓存,那么代码出现问题,在缓存期内无法修改问题。
问题:当js和css同时使用一个hash值没如果重新打包会导致会有缓存失效,而我只改动了一个文件
chunkhash: 根据chunk生成hash,如果打包来源于同一个chunk(在一个文件中引入),那么hash值就一样
问题:js和css hash还是一样,因为css是在js中引入的(相互引用就是同一个hash值),所以同属于一个chunk
contenthash: 会根据文件的内容生成hash值,不同文件的hash值一定不一样 --> 代码上线运行缓存更好使用


tree shaking: 去除无用代码
    前提:  1. 必须使用ES6 模块化
            2.开启production环境
    作用:减少代码体积
    在package.json中配置
    "sideEffects":false 所有代码都没有副作用(都可以进行tree shaking)
    问题:可能会吧css @babel/polyfill 等文件干掉
    所以:"sideEffects":["*.css","*.less"] 这样写去排除一些文件


PWA:渐进式网络开发应用程序(离线可访问)
workbox ---> workbox-webpack-plugin


多进程打包:thread-loader 那个东西启动多进程,就把它放进去,一般给babel-loader用


dll 技术:对某些(第三方库jQuery,react,vue ... )进行单独打包
新建dll 文件夹
新建webpack.dll.js
当运行 webpack  时,默认查找webpack.config.js文件
需求运行webpack --config webpack.dll 运行webpack.dll这个配置文件

const {resolve} = require('path')
const webpack = require('webpack')
module.exports = {
    entry:{
        // 最终打包生成的[name] -->jquery,对jQuery进行单独打包,需要单独打包什么库,就在这里配置
        jquery: ['jquery]
    },
    output:{
        filename:'[name].js',
        path:resolve(__dirname,'dll'),
        library:'[name]_[hash:10]',   // 打包的库里面向外暴露的内容叫什么名字
    },
    plugins:[
        // 打包生成manifest.json 一个映射关系
        new webpack.DllPlugin({
          name:[name]_[hash:10], // 映射库的暴露内容名称
          path: resolve(__dirname,'dll/manifest.json')   // 输出文件来路径
        })
    ],
    mode:'production'
}
// 这里做完过后主要配置也要变动
*/
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
const webpack = require('webpack')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')
module.exports = {
    //webpack 配置
    // 入口起点
    entry: ['./src/index.js', './src/index.html'],
    // 输出路径
    output: {
        // filename: '[name].[contenthash:10].js',文件名,来输出,多入口时使用
        filename: 'built.[contenthash:10].js',
        path: resolve(__dirname, 'build')
    },
    module: {
        rules: [
            // 详细loader配置,从下到上依次执行
            {
                /*
                语法检查  eslint-loader 依赖于 eslint
                设置检查规则: package.json中eslintConfig中设置
                airbnb -->eslint-config-airbnb-base eslint-plugin-import  需要下载
                // airbnb 检查风格 --> 一个库
                "eslintConfig":{
                    "extends": "airbnb-base"
                }
                // eslint-disable-next-line  下一行代码不进行eslint检查
                */
                test: /\.js$/,  // 只针对js文件检查,只检查自己写的源代码
                exclude: /node_modules/, // 必须排除第三方依赖,不然会报错
                enforce: 'pre',  // 优先执行
                loader: 'eslint-loader',
                options: {
                    // 自动修复eslint错误,就不需要手动去修复了
                    fix: true
                }
            },
            {
                /*oneOf 以下loader 只会匹配一个,主要提高构建速度,不会有几个loader就过几个loader,
                所以不能有两项loader处理同一项文件,所以部分需要提取出去,
                */
                oneOf: [
                    {
                        test: /\.css$/,  // 匹配.css结尾的文件
                        use: [           // use 表示使用什么loader
                            //'style-loader',  // 创建style标签,将js中的样式资源进行插入,添加到head中生效
                            MiniCssExtractPlugin.loader, // 取代style-loader,用是将多个css文件合并成一个css文件,及将css提成一个单独的文件
                            'css-loader', // 将css文件变成commonjs模块加载到js中,里面内容是样式字符串

                            // css兼容性处理postcss--》postcss-loader protcss-preset-env
                            /*
                            第二种找到package.json中添加browserslist配置
                            "browserslist":{
                                // 开发环境下兼容主流浏览器
                                "development":[
                                  "last 1 chrome version",
                                  "last 1 firefox version",
                                  "last 1 safari version"
                                ],
                                // 默认看生产环境
                                "productin":[
                                  ">0.2%", //兼容市场份额大于0.2的浏览器
                                  "not dead", //已经死去的浏览器不兼容
                                  "not op_mini all" //不要op_mini浏览器
                                 
                                ]
                              }
                              */
                            // 'postcss-loader', //使用loader默认配置这样写就行了
                            {
                                // 自己配置loader
                                loader: 'postcss-loader',
                                options: {
                                    ident: 'postcss',
                                    plugins: () => [
                                        require('protcss-preset-env')()
                                    ]
                                }
                            }

                        ]
                    },
                    {
                        test: /\.less$/,
                        use: [
                            'style-loader',  // 创建style标签,将js中的样式资源进行插入,添加到head中生效
                            'css-loader',  // 将css文件变成commonjs模块加载到js中,里面内容是样式字符串
                            'less-loader'    // 将less文件编译成css文件
                        ]
                    },
                    {
                        // 图片资源处理,处理不了html中的img标签中的图片
                        test: /\.(jpg|png|gif)$/,
                        // 使用一个loader,需要下载url-loader 和 file-loader --》url-loader依赖于file-loader
                        loader: 'url-loader',
                        options: {
                            // 图片小于8kb时,会被处理成base64 (这里写着8,项目根据实际来设置这个值)
                            // 优点:减少请求数量(减轻服务器压力),缺点:图片体积会变大
                            limit: 8 * 1024,
                            // 问题:url-loader模式使用es6模块化解析,而html-loader引入图片commonjs
                            // 解析时会出问题:[object Module]
                            // 解决关闭url-loader的es6模块化,使用commonjs解析
                            esModule: false,
                            // 给图片重命名[hash:10]取图片的hash的前10位
                            // [ext] 取文件原来的扩展名
                            name: '[hash:10].[ext]',
                            outputPath: 'img'  // 指定图片输出路径,其他资源也是一样的方法

                        }
                    },
                    {
                        // 处理html中img中的图片,负责引入img,从而能被url-loader进行处理
                        test: /\.html$/,
                        loader: 'html-loader'
                    },

                    {
                        // 打包其他资源除了html,css,js/img等其他资源
                        //排除css/js/html资源,想要排除的就在这里写清楚
                        exclude: /\.(css|js|html|less|jpg|png|gif)/,
                        loader: 'file-loader',
                        options: {
                            name: '[hash:10].[ext]'
                        }
                    },

                    {
                        /*
                        js兼容性处理 babel-loader @babel/prest-env @babel/core  下载第三方
                            1.基本的js兼容性处理 -->  @babel/prest-env 
                            问题:只能转换基本语法,不能处理promise等
                            2.全部js兼容性处理 --> @babel/polyfill(下载) --> 
                            使用 通过 import '@babel/polyfill' 在源代码js文件中引入
                            问题:一次性将所有兼容性代码引入,体积变大了
                            3.按需加载兼容性 --> core-js(下载)  使用第三种方案,就需要注释第二种方案
                        */
                        test: /\.js$/,
                        exclude: /node_modules/, //排除第三方node_modules 里的所有文件
                        use: [
                            /*
                            开启多进程打包
                            进程启动大概600ms,进程通信也需要时间
                            只有工作消耗时间比较长,才需要开启多进程打包
                            一般js比较消耗时间
                            也可以通过具体配置:指定开启多少个进程
                            workers: 2  ...
                            */
                            'thread-loader',
                            {
                                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'
                                                }
                                            }
                                        ]
                                    ],
                                    // 开启bebel缓存,第二次构建时,会读取之前的缓存
                                    cacheDirectory: true
                                }
                            }
                        ]
                    }
                ]
            }
        ]
    },
    plugins: [
        //详细plugins配置
        // html-webpack-plugin(打包html资源) 默认会创建一个空的HTML文件,自动引入打包输出的所有资源(JS/CSS)
        // 需求:需要有结构的HTML,所以需要加配置
        new HtmlWebpackPlugin({
            // 功能:复制'./src/index.html' 文件,并自动引入打包输出所以的资源(JS/CSS)
            template: './src/index.html',
            // 压缩html
            minify: {
                // 移除空格
                collapseWhitespace: true,
                // 移除注释
                removeComments: true
            }
        }),
        // 处理css
        new MiniCssExtractPlugin({
            filename: 'css/main.[contenthash:10].css'  // 多个css文件合并成一个主css文件,并对输出的文件进行重命名
        }),
        // 压缩css文件
        new OptimizeCssAssetsWebpackPlugin(),
        new WorkboxWebpackPlugin.GenerateSW({
            /*
            帮助serviceworker快速启动
            删除旧的serviceworker
            插件就会serviceworker的配置文件,通过配置文件serviceworker,在入口文件中注册serviceworker
            还要处理兼容性问题
            在入口文件index.js 中添加
            if('serviceWorker' in navigator) {
                window.addEventListener('load',()=>{
                    navigator.serviceWorker
                    .register('./service-worker.js')
                    .then(()=>{
                        console.log('sw注册成功了')
                    })
                    .catch(()=>{
                        console.log('sw注册失败了')
                    })
                })
            } 
            注意这里如果这里配置了eslint 可能会不识别navigator  window 等浏览器全局变量,所以要在package中添加配置
             // "browser": true 表示支持浏览器全局变量
             "eslintConfig":{
                    "extends": "airbnb-base",
                    "env":{
                        "browser": true
                    }
                }

             再注意:   sw代码必须运行在服务器上
                -- npm i serve -g
                serve -s build 启动一个服务器,将build目录下的资源作为静态资源暴露出去
            */
            clientsClaim: true,
            skipWaiting: true
        }),
        // 告诉webpack哪些第三方库不参与打包,但是不参与打包,就会没有这些引用包,所以就需要另一个配置
        new webpack.DllReferencePlugin({
            manifest: resolve(__dirname, 'dll/manifest.json')
        }),
        // 将不参与打包的文件输出出去,并在html中自动引入该资源
        new AddAssetHtmlWebpackPlugin({
            filepath: resolve(__dirname, 'dll/jquery.js')
        })
    ],
    //模式
    mode: 'development',
    // 生产环境下会自动压缩js代码,不需要做其他操作
    // mode: 'production'


    // 开发服务器devServer :用来自动化(自动编译,自动打开浏览器,自动刷新浏览器)
    // 只会在内存中编译打包,不会任何输出
    // 启动DevServer指令: npx webpack-dev-server,也可以在package.json 中配置
    // 需要下载webpack-dev-server
    devServer: {
        contentBse: resolve(__dirname, 'build'),
        // 启动gzip压缩
        compress: true,
        // 端口
        port: 8080,
        //自动打开浏览器
        open: true,
        // 开启HMR功能,开启模块热更新
        hot: true,
        // 不显示服务器日志信心
        clientLogLevel: 'none',
        // 出错了,不要全屏提示
        overlay: false,
        // 服务器代理 -->开发环境下解决跨域问题
        //    一旦devServer(8080)服务器接收到/api/xxx的请求,就会把这个请求转发到服务器(3000 )
        proxy: {
            '/api': {
                target: 'http://localhost:3000',
                // 发送请求时路径重写;将/api/xxx --> /xxx (及去掉/api)
                pathRewrite: {
                    '^/api': ''
                }
            }
        }
    },
    devtool: 'source-map',

    // 代码按需加载,可以将node_modules 中代码单独打包成一个chunk最终输出,自己的东西单独放
    // 自动分析多入口chunk中,有没有公共文件,如果有会单独打包成一个chuank
    optimization: {
        splitChunks: {
            chunks: 'all'
        },

        minimizer: [
            //配置生产环境的压缩方案:js和css
            new TerserWebpackPlugin({
                // 开启缓存
                cache: true,
                // 开启多进程打包
                parallel: true,
                // 启动source-map
                sourceMap: true
            })
        ]
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值