Webpack 简介

201 阅读11分钟

1.webpack 是什么

webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。

在webpack 看来, 前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理。
它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。

通常我们在讨论时,bundle 指的是所有模块都打包进入的单个文件,而 chunk 指的是按照某种规则的模块集合,chunk 的体积大于单个模块,同时小于整个 bundle

2 webpack 五个核心概念

2.1 Entry

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

2.2 Output

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

2.3 Loader

Loader:让 webpack 能够去处理那些非 JS 的文件,比如样式文件、图片文件(webpack 自身只理解
JS)

2.4 Plugins

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

Mode(模式):

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

npm i webpack webpack-cli -D  安装webpack
webpack --stats 查看详细的打包信息
npm uninstall webpack webpack-cli -g 全局卸载webpack
npx webpack //当当前文件夹中node_modules中没有webpack时就会去上一级找有没有webpack

3.自定义webpack

npx webpack --entry ./src/index.js --mode production

配置文件配置webpack

在项目根目录下新建一个webpack.config.js的文件。使用common.js的语法

//webpack.config.js
const path = require('path')
module.exports = {
    entry: "./src/index.js",
    output: {
        filename: "bundle.js",
        //path.resolve(__dirname,"xxx")__dirname当前文件路径
        pathpath.resolve(__dirname, "./dist")
    },
    mode: "none"
}
然后执行npx webpack

4.自动引入资源

插件plugins的作用

HtmlWebpackPlugin

npm i html-webpack-plugin -D //安装插件

配置HtmlWepackPlugin插件

const path = require('path')
const HtmlWepackPlugin = require("html-webpack-plugin")
const { Template } = require('webpack')
module.exports = {
    entry"./src/index.js",
    output: {
        filename"bundle.js",
        //path.resolve(__dirname,"xxx")__dirname当前文件路径
        path: path.resolve(__dirname, "./dist")
    },
    plugins: [
        new HtmlWepackPlugin({
            // 以现有的html模版页面打包
            template"./index.html",
            // 打包后的html
            filename'app.html',
            // 在body中生成script标签
            inject'body'
        })
    ],
    mode"development",
}

清除之前的打包内容

output: {
    filename: "bundle.js",
    //path.resolve(__dirname,"xxx")__dirname当前文件路径
    pathpath.resolve(__dirname, "./dist"),
    // 清除之前的打包内容
    clean: true
},

5.搭建开发环境

sourceMap

const path = require('path')
const HtmlWepackPlugin = require("html-webpack-plugin")
const { Template } = require('webpack')
module.exports = {
    entry"./src/index.js",
    output: {
        ...
    },
    // 通过source-map可以追踪错误源码的出处
    devtool"inline-source-map",
    plugins: [
        ...
    ],
    mode"development",

}

实时编译

npx webpack --watch //--watch 参数会在源文件发生变动的时候起到自动执行wepack编译的效果

Webpack-dev-serve

提供了一个基本的web serve,具有实时重新加载的功能live reloading,当文件发生修改,浏览器侦听到文件的修改自动刷新

npm i webpack-dev-server -D //安装
npx webpack-dev-server  // 启动
npx webpack-dev-server --open //启动 并自动打开浏览器

Wepack-dev-server 并没有真正输出任何物理文件,它把输出后的bundle文件放到了内存里

6.资源模块

asset module

asset module type

asset/rource

配置打包输出文件名

const path = require('path')
const HtmlWepackPlugin = require("html-webpack-plugin")
const { Template } = require('webpack')
module.exports = {
    entry"./src/index.js",
    output: {
        // 配置打包输出文件名 contenthash哈希,ext文件名后缀
        assetModuleFilename'images/[contenthash][ext]'
    },
    // 通过source-map可以追踪错误源码的出处
    devtool"inline-source-map",
    plugins: [
        ...
    ],
    mode"development",

}

模块匹配处理规则

module: {
    rules: [
        {
            test: /.png$/,
            type: "asset/resource",
            //优先级高于output中assetModuleFilename的规则
            generator: {
                filename: "images/test.png"
            }
        }
    ]
},

asset/inline

{
    test: /.svg$/,
    // 将文件转成base64 data-url
    type"asset/inline",
},

asset/source

 {
      test: /.txt$/,
      type"asset/source",
  },

asset

{
    test: /.jpg$/,
    // 在 "asset/resource" 和  // 文件base64 data-url之间选择
    // 当大于8k会创建文件,可以调节临界值来作为是否要生成文件的依据
    type"asset",
    parser: {
        dataUrlCondition: {
            maxSize: 4 * 1024 * 1024
        }
    }
},

7.管理资源

loader 加载器

处理样式文件

npm i css-loader -D  //安装css

配置文件

const path = require('path')
const HtmlWepackPlugin = require("html-webpack-plugin")

module.exports = {
    entry"./src/index.js",
    output: {
       ...
    },
    devtool"inline-source-map",
    plugins: [
      ...
    ],
    devServer: {
        static'./dist'
    },
    module: {
        rules: [
            ...
            //css-loader 加载css
             {
                // test: /.css$/,
                // 先css-loader编译css文件,再用style-loader加载到页面上
                // use: ["style-loader", "css-loader"]
                 test/.(css|less)$/,
                // 先用less-loader解析less语法,然后用css-loader编译css文件,再用style-loader将style标签加载到                                    页面上的header标签下
                use: ["style-loader""css-loader"'less-loader']
            }
        ]
    },

    mode"development",

}
npm i css-loader style-loader -D
// 解析less需要用到less-loader 和less-loader
npm i less-loader less -D

抽离和压缩css

npm i mini-css-extract-plugin -D //安装抽离插件

配置文件

const path = require('path')
const HtmlWepackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
module.exports = {
    entry"./src/index.js",
    output: {
        ...
    },
    // 通过source-map可以追踪错误源码的出处
    devtool"inline-source-map",
    plugins: [
           ...
         new MiniCssExtractPlugin({
            // 定义抽离后的css文件名
            filename'styles/[contenthash].css'
        })
    ],
    devServer: {
        ...
    },
    module: {
        rules: [
           ...
            {
                test/.(css|less)$/,
                // 先用less-loader解析less语法,然后用css-loader编译css文件,
                //再用MiniCssExtractPlugin.loader                                
                //将样式抽离到单独的文件中,生成.css文件会在打包后的html新增link标签并且引入抽离的css文件
                use: [MiniCssExtractPlugin.loader"css-loader"'less-loader']
            }

        ]
    },

    mode"development",

}
npm i css-minimizer-webpack-plugin -D  // 安装压缩css

配置文件

const path = require('path')
const HtmlWepackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const MiniMiZerCssPlugin = require("css-minimizer-webpack-plugin")
module.exports = {
    entry"./src/index.js",
    output: {
        filename"bundle.js",
        //path.resolve(__dirname,"xxx")__dirname当前文件路径
        path: path.resolve(__dirname, "./dist"),
        // 清除之前的打包内容
        cleantrue,
        // 配置打包输出文件名 contenthash哈希,ext文件名后缀
        assetModuleFilename'images/[contenthash][ext]'
    },
    // 通过source-map可以追踪错误源码的出处
    devtool"inline-source-map",
    plugins: [
       ...
    ],
    devServer: {
        static'./dist'
    },
    module: {
        ...
    },
    // 优化
    optimization: {
        minimizer: [
            new MiniMiZerCssPlugin()
        ]
    },
    // 压缩需要将mode改为production
    mode"production",
}

在css中加载图片

// style.css
.block-bg {
    border-colorurl("./asset/logo.svg"!important;
}
//index.js
block.classList.add("block-bg")

加载font字体

const path = require('path')
const HtmlWepackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const MiniMiZerCssPlugin = require("css-minimizer-webpack-plugin")
module.exports = {
    entry"./src/index.js",
    output: {
        ...
    },
    // 通过source-map可以追踪错误源码的出处
    devtool"inline-source-map",
    plugins: [
        ...
    ],
    devServer: {
        static'./dist'
    },
    module: {
        rules: [
                ...
            {
                test/.(woff|woff2|eot|ttf|otf)$/,
                type"asset/resource"
            }

        ]
    },
    // 优化
    optimization: {
        ...
    },
    mode"development",
}

加载数据

npm i csv-loader xml-loader -D //安装loader
  ...
module.exports = {
    entry: "./src/index.js",
    output: {
        ...
    },
    // 通过source-map可以追踪错误源码的出处
    devtool: "inline-source-map",
    plugins: [
        ...
    ],
    devServer: {
        static: './dist'
    },
    module: {
        rules: [
            ...
            // 会转成数组
            {
                test: /.(csv|tsv)$/,
                use: "csv-loader"
            },

            // 会转成obj
            {
                test: /.xml$/,
                use: "xml-loader"
            }

        ]
    },
    mode: "development",
}

自定义的JSON模块parser

npm i yaml toml json -D  // 
// 引入yaml
const yaml = require("yaml")
module.exports = {
    entry: "./src/index.js",
    output: {
        ...
    },
    // 通过source-map可以追踪错误源码的出处
    devtool: "inline-source-map",
    plugins: [
        ...
    ],
    devServer: {
        static'./dist'
    },
    module: {
        rules: [
            ...
            {
                test: /.yaml$/,
                type: "json",
                parser: {
                    parse: yaml.parse
                }

            }
        ]
    },

}

8.使用babel-loader

ES6语法转化 使低版本的浏览器也能执行es6语法!

npm install babel-loader@8.0.0-beta.0 @babel/core @babel/preset-env
// 配置文件
{
    test/.js$/,
    exclude/node_modules/,
    use: {
        loader'babel-loader',
        options: {
            presets: ['@babel/preset-env']
        }
    }
}

9.代码分离

入口起点

配置文件

 entry: {
        //    两个打包入口
        index: "./src/index.js",
        another: "./src/another-module.js"
    },
    output: {
        // 打包后的名字
        filename: "[name].bundle.js",
        //path.resolve(__dirname,"xxx")__dirname当前文件路径
        path: path.resolve(__dirname, "./dist"),
        // 清除之前的打包内容
        clean: true,
        // 配置打包输出文件名 contenthash哈希,ext文件名后缀
        assetModuleFilename: 'images/[contenthash][ext]'
    },

防止重复

多入口配置文件1

 entry: {
    index: {
        import: './src/index.js',
        // 依赖shared模块
        dependOn: "shared"
    },
    another: {
        import: './src/another-module.js',
        // 将共享的文件定义出来
        dependOn: "shared"
    },
    //将其他模块都用到的依赖单独抽离出来 
    shared: "lodash"

},

使用webpack内置插件split-chunks-Plugin

const path = require('path')
const HtmlWepackPlugin = require("html-webpack-plugin")

module.exports = {
    entry: {
        index'./src/index.js',
        another'./src/another-module.js'
    },
    optimization: {
        splitChunks: {
            chunks"all"
        }
    }

}

动态导入

//利用Es6提供的import语法
async function getComponent() {
    const element = document.createElement('div');
    const { default: _ } = await import('lodash');
    element.innerHTML = _.join(['Hello''webpack'], ' ');
    return element;
}
getComponent().then((ele) => {
    document.body.appendChild(ele)
})

应用

懒加载
const btn = document.createElement("button")
btn.textContent = "点击执行加法运算"
btn.addEventListener("click"async () => {
    const { add } = await import(/*webpackChunkName:'math'*/"./math")
    console.log(add(45))
})
document.body.appendChild(btn)
btn.addEventListener("click"async () => {
        //webpackPrefetch:true 告诉浏览器进行预获取在网络空闲时
    const { add } = await import(/*webpackChunkName:'math',webpackPrefetch:true*/"./math")
    console.log(add(45))
})
document.body.appendChild(btn)
btn.addEventListener("click"async () => {
        //webpackPreload:true 告诉浏览器进行预获取在网络空闲时
    const { add } = await import(/*webpackChunkName:'math',webpackPreload:true*/"./math")
    console.log(add(45))
})
document.body.appendChild(btn)

10.缓存

通过contenthash打包生成文件名,来进行缓存处理

 output: {
    // [name] subsitution 可替换的模版字符串
    filename: "[name].[contenthash].js",
    //path.resolve(__dirname,"xxx")__dirname当前文件路径
    path: path.resolve(__dirname, "dist"),
    // 清除之前的打包内容
    clean: true,
    // 配置打包输出文件名 contenthash哈希,ext文件名后缀
    assetModuleFilename: 'images/[contenthash][ext]'
},

缓存第三库

 optimization: {
    runtimeChunk: 'single',
    splitChunks: {
        cacheGroups: {
            vendor: {
                test: /[\/]node_modules[\/]/,
                name: 'vendors',
                chunks: 'all',
            },
        },
    },
},

将所有的js文件放到一个文件夹下

output: {
        // 全部放到一个文件夹下
    filename: 'scripts/[name].[contenthash].js',
    pathpath.resolve(__dirname, 'dist'),
    clean: true,
},

11.拆分开发环境和生产环境配置

公共路径

output: {
    filename: 'scripts/[name].[contenthash].js',
    pathpath.resolve(__dirname, 'dist'),
    clean: true,
    // 指定资源的基础路径
    publicPath: "http://localhost:8080/"
},

环境变量

const path = require('path')
const HtmlWepackPlugin = require("html-webpack-plugin")

module.exports = (env) => {
    console.log(env)
    return {
        mode: env.production ? "production" : "development",
        ...
    }
}

压缩代码

npm i terser-webpack-plugin -D // 
optimization: {
    minimizer: [
        new TerserPlugin()
    ],
},

12.拆分配置文件

//根目录下新建/config/webpack.config.dev.js
//执行 npx webpack --config config/webpack.config.dev.js
// 修改路径
output: {
    filename: 'scripts/[name].js',
    pathpath.resolve(__dirname, '../dist'),
    clean: true,
},

开发环境配置

// /config/webpack.config.dev.js
const path = require('path')
const HtmlWepackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
console.log("webpack.config.dev.js", path.resolve(__dirname, "../dist"))
module.exports = {
    entry: {
        index'./src/index.js',
        another"./src/another-module.js"
    },
    output: {
        filename'scripts/[name].js',
        path: path.resolve(__dirname, '../dist'),
        cleantrue,
    },
    mode"development",
    devtool"inline-source-map",
    plugins: [
        new HtmlWepackPlugin({
            // 以现有的html模版页面打包
            template"./index.html",
            // 打包后的html
            filename'app.html',
            // 在body中生成script标签
            inject'body'
        })
    ],
    devServer: {
        static'./dist'
    },
    module: {
        rules: [
            {
                test/.png$/,
                // 文件路径
                type"asset/resource",
                generator: {
                    filename"images/[contenthash][ext]"
                }
            },
            {
                test/.svg$/,
                // 文件base64 data-url
                type"asset/inline",
            },
            {
                test/.txt$/,
                type"asset/source",
            },
            {
                test/.jpg$/,
                // 在 "asset/resource" 和  // 文件base64 data-url之间选择
                // 当大于8k会创建文件,可以调节临界值来作为是否要生成文件的依据
                type"asset",
                parser: {
                    dataUrlCondition: {
                        maxSize4 * 1024 * 1024
                    }
                }
            },
            {
                test/.(css|less)$/,
                // 先用less-loader解析less语法,然后用css-loader编译css文件,
                //再用MiniCssExtractPlugin.loader                                
                //将样式抽离到单独的文件中,生成.css文件会在打包后的html新增link标签并且引入抽离的css文件
                use: [MiniCssExtractPlugin.loader"css-loader"'less-loader']
            },
            {
                test/.js$/,
                exclude/node_modules/,
                use: {
                    loader'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            }

        ]
    },
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {
                    test/[\/]node_modules[\/]/,
                    name'vendors',
                    chunks'all',
                },
            },
        },
    },
}

生产环境配置

// /config/webpack.config.prod.js
const path = require('path')
const HtmlWepackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const MiniMiZerCssPlugin = require("css-minimizer-webpack-plugin")
const TerserPlugin = require("terser-webpack-plugin")
module.exports = {
    entry: {
        index'./src/index.js',
        another"./src/another-module.js"
    },
    output: {
        filename'scripts/[name].[contenthash].js',
        path: path.resolve(__dirname, '../dist'),
        cleantrue,
        publicPath"http://localhost:8080/"
    },
    mode"production",
    module: {
        rules: [
            {
                test/.png$/,
                // 文件路径
                type"asset/resource",
                generator: {
                    filename"images/[contenthash][ext]"
                }
            },
            {
                test/.svg$/,
                // 文件base64 data-url
                type"asset/inline",
            },
            {
                test/.txt$/,
                type"asset/source",
            },
            {
                test/.jpg$/,
                // 在 "asset/resource" 和  // 文件base64 data-url之间选择
                // 当大于8k会创建文件,可以调节临界值来作为是否要生成文件的依据
                type"asset",
                parser: {
                    dataUrlCondition: {
                        maxSize4 * 1024 * 1024
                    }
                }
            },
            {
                test/.(css|less)$/,
                // 先用less-loader解析less语法,然后用css-loader编译css文件,
                //再用MiniCssExtractPlugin.loader                                
                //将样式抽离到单独的文件中,生成.css文件会在打包后的html新增link标签并且引入抽离的css文件
                use: [MiniCssExtractPlugin.loader"css-loader"'less-loader']
            },
            {
                test/.js$/,
                exclude/node_modules/,
                use: {
                    loader'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            }

        ]
    },
    plugins: [
        new HtmlWepackPlugin({
            // 以现有的html模版页面打包
            template"./index.html",
            // 打包后的html
            filename'app.html',
            // 在body中生成script标签
            inject'body'
        })
    ],
    optimization: {
        minimizer: [
            new TerserPlugin(),
            new MiniMiZerCssPlugin()
        ],
        runtimeChunk'single',
        splitChunks: {
            cacheGroups: {
                vendor: {
                    test/[\/]node_modules[\/]/,
                    name'vendors',
                    chunks'all',
                },
            },
        },
    },
}

启动webpack-dev-serve

npx webpack serve --config config/webpack.config.dev.js --open

npm 脚本

//package.json
 "scripts": {
    "test""echo "Error: no test specified" && exit 1",
    "start""webpack serve --config config/webpack.config.dev.js --open",
    "build""webpack --config config/webpack.config.prod.js"
  },
// 可以关闭删除时的打包提示信息warning
performance: {
    hints: false
}

提取公共配置

const path = require('path')
const HtmlWepackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
console.log("webpack.config.common.js", path.resolve(__dirname, "../dist"))
module.exports = {
    entry: {
        index'./src/index.js',
        another"./src/another-module.js"
    },
    output: {
        path: path.resolve(__dirname, '../dist'),
        cleantrue,
        // 配置打包输出文件名 contenthash哈希,ext文件名后缀
        assetModuleFilename'images/[contenthash][ext]'
    },
    plugins: [
        new HtmlWepackPlugin({
            // 以现有的html模版页面打包
            template"./index.html",
            // 打包后的html
            filename'app.html',
            // 在body中生成script标签
            inject'body'
        })
    ],
    module: {
        rules: [
            {
                test/.png$/,
                // 文件路径
                type"asset/resource",
                generator: {
                    filename"images/[contenthash][ext]"
                }
            },
            {
                test/.svg$/,
                // 文件base64 data-url
                type"asset/inline",
            },
            {
                test/.txt$/,
                type"asset/source",
            },
            {
                test/.jpg$/,
                // 在 "asset/resource" 和  // 文件base64 data-url之间选择
                // 当大于8k会创建文件,可以调节临界值来作为是否要生成文件的依据
                type"asset",
                parser: {
                    dataUrlCondition: {
                        maxSize4 * 1024 * 1024
                    }
                }
            },
            {
                test/.(css|less)$/,
                // 先用less-loader解析less语法,然后用css-loader编译css文件,
                //再用MiniCssExtractPlugin.loader                                
                //将样式抽离到单独的文件中,生成.css文件会在打包后的html新增link标签并且引入抽离的css文件
                use: [MiniCssExtractPlugin.loader"css-loader"'less-loader']
            },
            {
                test/.js$/,
                exclude/node_modules/,
                use: {
                    loader'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            }

        ]
    },
    optimization: {
        runtimeChunk'single',
        splitChunks: {
            cacheGroups: {
                vendor: {
                    test/[\/]node_modules[\/]/,
                    name'vendors',
                    chunks'all',
                },
            },
        },
    },
}
 npm i webpack-merge -D  // 安装依赖
/config/webpack.config.js
const { merge } = require("webpack-merge")
const commonConfig = require("./webpack.config.common")
const prodConfig = require("./webpack.config.prod")
const devConfig = require("./webpack.config.dev")

module.exports = (env) => {
    switch (true) {
        case env.development:
            return merge(commonConfig, devConfig)
        case env.production:
            return merge(commonConfig, prodConfig)
        default:
            new Error("no matching configuration was found")
    }
}

// 修改脚本
"scripts": {
    "start""webpack serve --config config/webpack.config.js --env development",
    "build""webpack --config config/webpack.config.js --env production"
  },

13.sourceMap

1.默认 "eval"

// webpack.config.js
2.devtool:"source-map",  // 在末尾加 //# sourceMappingURL=main.js.map
// main.js.map
{
    "version"3,
    "file""main.js",
    "mappings""AAAAA,QAAQC,IAAI",
    "sources": [
        "webpack://01-sourcemap/./app.js"
    ],
    "sourcesContent": [
        "console.log("hello webpack")"
    ],
    "names": [
        "console",
        "log"
    ],
    "sourceRoot"""
}

3.devtool:"hidden-source-map"// 在末尾不追加链接 在控制台无法看到源代码行数
// main.js.map
{
    "version"3,
    "file""main.js",
    "mappings""AAAAA,QAAQC,IAAI",
    "sources": [
        "webpack://01-sourcemap/./app.js"
    ],
    "sourcesContent": [
        "console.log("hello webpack")"
    ],
    "names": [
        "console",
        "log"
    ],
    "sourceRoot"""
}
4.devtool:"inline-source-map",  //生产一个dataURL形式的sourceMappingURL 可以锁定代码行数 不生成main.js.map 

//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsIm1hcHBpbmdzIjoiQUFBQUEsUUFBUUMsSUFBSSIsInNvdXJjZXMiOlsid2VicGFjazovLzAxLXNvdXJjZW1hcC8uL2FwcC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zb2xlLmxvZyhcImhlbGxvIHdlYnBhY2tcIikiXSwibmFtZXMiOlsiY29uc29sZSIsImxvZyJdLCJzb3VyY2VSb290IjoiIn0=


5.devtool:"hidden-source-map"//每个module会通过eval()来执行,并生成dataURL形式的sourceMappingURL

eval("console.log("hello webpack")//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9hcHAuanMuanMiLCJtYXBwaW5ncyI6IkFBQUEiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8wMS1zb3VyY2VtYXAvLi9hcHAuanM/OWE3OCJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zb2xlLmxvZyhcImhlbGxvIHdlYnBhY2tcIikiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./app.js\n");

6.devtool:"cheap-source-map" //生成一个没有列信息的source-map,不包含loader的sourcemap 追踪不到代码行数
{
    "version"3,
    "file""main.js",
    //只保留行信息
    "mappings"";;;;;AAAA",
    "sources": [
        "webpack://01-sourcemap/./app.js"
    ],
    "sourcesContent": [
        "console.log("hello webpack")"
    ],
    "names": [],
    "sourceRoot"""
}

7.devtool:"cheap-module-source-map" //生成一个没有列信息的source-map,不包含loader的sourcemap 可以追踪代码行数

14.devServer

npx webpack serve  // 启动开发服务器
配置文件
const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")

module.exports = {
    mode: "development",
    entry: "./app.js",
    output: {
        publicPath: "/"
    },
    devServer: {
        static: path.resolve(__dirname, './dist'),
        // 是否进行压缩
        compress: true,
        // 服务器端口
        port: 3000,
        host: "0.0.0.0",
        // 在Response Headers 中添加信息
        headers: {
            "x-access-token"'abc123'
        },
        proxy: {
            // 访问/api开头的借口,就会转发到http://localhost:9000
            "/api""http://localhost:9000"
        },
        // 使用https
        // https: true
        http2: true,
        // 路径失败跳回主页
        historyApiFallback: true
    },
    plugins: [
        new HtmlWebpackPlugin()
    ],
}

15.模块热替换与热加载

const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const { template } = require("lodash")

module.exports = {
    mode"development",
    entry"./app.js",
    devServer: {
        // 模块热替换
        hotfalse,
        // 热加载
        liveReloadfalse
    },
    plugins: [
        new HtmlWebpackPlugin(
            {
                template"./index.html"
            }
        )
    ],
    module: {
        rules: [
            {
                test/.css$/,
                // 先css-loader编译css文件,再用style-loader加载到页面上
                use: ["style-loader""css-loader"]
                // test: /.(css|less)$/,
                // 先用less-loader解析less语法,然后用css-loader编译css文件,再用style-loader将style标签加载到                                    页面上的header标签下
                // use: ["style-loader", "css-loader", 'less-loader']
            }
        ]
    },
}

16.EsLint

npm i eslint -D  // 安装 也可以使用。npm init @eslint/config

// 配置eslint
chengpeng@chengpeng 04-eslint % npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
npx: 41 安装成功,用时 4.251 秒
? How would you like to use ESLint? … 
  To check syntax only
❯ To check syntax and find problems
  To check syntax, find problems, and enforce code style

npx eslint ./src  //检测代码规范

配置文件

const HtmlWebpackPlugin require('html-webpack-plugin');
const ESLintPlugin require('eslint-webpack-plugin');
const { resolve } = require('path');

module.exports = {
  mode: 'development',
  entry: './src/app.js',
  plugins: [
    new HtmlWebpackPlugin(),
    new ESLintPlugin({
      extensions: ['js'],
      contextresolve('src'),
      exclude'/node_modules',
      fixtrue,
    }),
  ],

};

husky

npm i husky -D //安装依赖
npx husky install  //安装husky
在.husky文件下新建一个pre-commit文件
内容为 
  npx eslint ./src
修改文件权限
chmod +x .husky/pre-commit
然后在git commit 的时候就会执行这个脚本

17.模块和依赖

模块解析

import Header from '/src/components/header' // 绝对路径
import Header from './components/header' //相对路径
import _ from 'lodash'  // 模块路径
const {resolve} = require('path')

module.exports = {
  mode:"development",
  entry:"./src/app.js",
  // 模块解析
  resolve:{
    alias:{
      "@":resolve(__dirname,"./src")
    },
    extensions:['.json','.js']
  },

}

External

const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
  mode:"development",
  entry:"./app.js",
  plugins: [
    new HtmlWebpackPlugin()
  ],

  externals:{

    jquery: [
      "https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js",
      "$"
    ]
  },
  externalsType:'script'
}

18.PostCss 与Css模块

npm i style-loader css-loader postcss-loader -D   // 安装loader
npm i autoprefixer -D // 安装插件
npm i postcss-nested -D// 安装插件

第一步:在package.json 在package.json使用 browserslist 字段

"browserslist": [
  ">1%",
  "last 2 versions"
]

第二步:新增 postcss.config.js

module.exports = {
  plugins: [
      //Autoprefixer是一款基于PostCSS插件,用于解析CSS并使用Can I Use中的值向CSS规则添加供应商前缀 。它是 Google        推荐的,可以实现css3代码自动补全,也可以运用到sass、less中
    require('autoprefixer'),
    // 支持嵌套语法
    require("postcss-nested")
  ]
}

// 配置文件

const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
  mode"development",
  entry: {
    app'./src/app.js',
  },
  plugins: [
    new HtmlWebpackPlugin(),
  ],
  module: {
    rules: [
      {
        test/.css$/,
        use: [
          "style-loader",
          // css 模块化
          {
            loader"css-loader",
            options: {
              modulestrue
            }
          },
          "postcss-loader"
        ]
      }
    ]
  }
}

19.Web Works

20.TypeScript

npm i typescript ts-loader  // 
npx tsc --init // init 生产tsconfig.json
 打开   "outDir""./",  修改为 "outDir""./dist",
配置文件
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
  mode"development",
  entry"./src/app.ts",
  output: {
    filename"bundle.js",
    path: path.resolve(__dirname, "dist")
  },
  plugins: [
    new HtmlWebpackPlugin()
  ],
  devtool"inline-source-map",
  module: {
    rules: [
      {
        test/.ts$/,
        use"ts-loader",
        exclude/node_modules/,
      }
    ]
  },
  resolve: {
   //模块解析优先级
    extensions: ['.ts''.js']
  }
}
ts使用lodash

npm i lodash @types/lodash

多页应用

自定义html模版

const path require("path");
const HtmlWebpackPlugin require("html-webpack-plugin")
module.exports = {
  mode: "development",
  entry: {
    main: {
      //打包入口
      import: [
        "./src/app.js",
        "./src/app2.js",
      ],
      // 依赖的模块
      dependOn: "lodash",
      // 打包路径
      filename: "chanel1/[name].js",
    },
    main2: {
      import: "./src/app3.js",
      dependOn: "lodash",
      filename: "chanel2/[name].js",
    },
    lodash: {
      import: "lodash",
      filename: "common/[name].js",
    },
  },
  output: {
    clean: true,
  },
  plugins: [
      // 模版一
    new HtmlWebpackPlugin({
        //模版title
      title"zcc大猪头",
      //打包模版
      template"./index.html",
      //js位置
      inject"body",
      //打包路径
      filename"chanel1/index.html",
      //需要的chunk
      chunks: ["main""lodash"]
    }),
    //模版二
    new HtmlWebpackPlugin({
      title"zcc2大猪头",
      template"./index2.html",
      inject"body",
      filename"chanel2/index2.html",
      chunks: ["main2""lodash"],
      publicPath"http:baidu.com"
    })
  ],
  devtool: "inline-source-map",
}

Tree-shaking

const HtmlWwbpackPlugin = require('html-webpack-plugin');
module.exports = {
  // mode: "development",
  mode: "production",
  entry: "./src/app.js",
  plugins: [
    new HtmlWwbpackPlugin()
  ],
  optimization: {
    usedExports: true
  }
}

webpack 是不能百分之百tree-shaking的

"sideEffects": [
  "*.css",
  "*.g.js"
],
//告诉webpack .css 和.g.js不能删除

PWA

Shimming

const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack')
module.exports = {
  mode"development",
  entry"./src/index.js",
  plugins: [
    new HtmlWebpackPlugin(
      { title'Progressive Web Application' }
    ),
    new webpack.ProvidePlugin({
      _"lodash"
    })
  ],
  module: {
    rules: [
      // 细粒度shimming
      {
        testrequire.resolve("./src/index.js"),
        use"imports-loader?wrapper=window"
      },
      // 全局导出
      {
        testrequire.resolve("./src/globals.js"),
        use"exports-loader?    type=commonjs&exports=file,multiple|helpers.parse|parse"
      },
    ]
  }
}

全局exports

polyfill

npm i babel-loader @babel/core @babel/preset-env -D
npm install  core-js@3 -D
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  mode: 'development',
  // mode: 'production',
  entry: "./src/index.js",
  plugins: [
    new HtmlWebpackPlugin(
      { title'Progressive Web Application' }
    ),
  ],

  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: {
          loader'babel-loader',
          options: {
            presets: [
              [
                "@babel/preset-env",
                { 
                  // polyfill 的目标浏览器
                  targets: [
                    "last 1 version",
                    "> 1%"
                  ],
                  useBuiltIns'usage',
                  corejs3
                }
              ]
            ]
          }
        }
      }
    ]
  }

}

创建Library