webpack 基础学习

341 阅读4分钟

1.定义

webpack是一个js的静态模块打包器module bundler。

从入口模块出发,递归查找所有文件的依赖,并入口和所有依赖打包成一个文件中。 是工程化自动化思想的体现。

2.安装

局部安装(建议,不与全局冲突)

npm init -y # 初始化npm配置⽂件
npm install --save-dev webpack # 安装核⼼库
npm install --save-dev webpack-cli # 安装命令⾏⼯具

# 安装的4.x稳定版本 npm i -D webpack@<version>
npm i -D webpack@4.44.0 
npm i -D webpack-cli@3.3.12
npm i -D webpack-dev-server@3.11.0

全局安装

# 安装webpack V4+版本时,需要额外安装webpack-cli
npm install webpack webpack-cli -g
# 检查版本
webpack -v
# 卸载
npm uninstall webpack webpack-cli -g

3.支持

  • webpack默认⽀持JS模块和JSON模块
  • ⽀持CommonJS Es moudule AMD等模块类型
  • webpack4⽀持零配置使⽤,但是很弱,稍微复杂些的场景都需要额外扩展,建议重写 例子:
# 创建资源目录
mkdir src
cd src
touch index.js index.json other.js 
# 创建配置文件
touch webpack.config.js

//index.js
const json = require("./index.json");//commonJS
import { add } from "./other.js";//es module
console.log(json, add(2, 3));
//index.json
{
    "name": "JOSN"
}
// other.js
export function add(n1, n2) {
    return n1 + n2;
}

//默认自动生成的配置信息 webpack.config.js
const path = require("path");
module.exports = {
    // 必填 webpack执⾏构建⼊⼝
    entry: "./src/index.js",
    output: {
        // 将所有依赖的模块合并输出到main.js
        filename: "main.js",
        // 输出⽂件的存放路径,必须是绝对路径
        path: path.resolve(__dirname, "./dist")
    }
};

4.启动

npx⽅式启动

偷懒方式启动,可以省去配置webpack.config.js

原理就是通过shell脚本在node_modules/.bin⽬录下创建⼀个软链接。

npx webpack 

npm script 启动

npm run test

5.配置说明

module.exports = {
    entry: "./src/index.js", //打包⼊⼝⽂件
    output: "./dist", //输出结构
    mode: "production", //打包环境
    module: {
        rules: [
            //loader模块处理
            {
                test: /\.css$/,
                use: "style-loader"
            }
        ]
    },
    plugins: [new HtmlWebpackPlugin()] //插件配置
}; 

entry

//单⼊⼝ SPA,本质是个字符串
entry: {
    main: './src/index.js'
}
//等价于
entry: "./src/index.js"

//数组也是单页面 最终只有一个bunlde
entry: ["./src/index.js","./src/login.js"] 


//多⼊⼝ entry是个对象 下面的output 通过[name]直接输出这里的命名index和login
entry: {
    index: "./src/index.js",
    login: "./src/login.js"
}

output

//单入口
output: {
    filename: "bundle.js",//输出⽂件的名称
    path: path.resolve(__dirname, "dist")//输出⽂件到磁盘的⽬录,必须是绝对路径
},
//多⼊⼝的处理 [name]对应上面的entry {index: 和 login:},如果直接写main.js 会报错,找不到多个文件关系
output: {
    filename: "[name][chunkhash:8].js",//利⽤占位符,⽂件名称不要重复
    path: path.resolve(__dirname, "dist")//输出⽂件到磁盘的⽬录,必须是绝对路径
},

mode

Mode⽤来指定当前的构建环境

  • production
  • development
  • none

使用

//1.配置定义 建议这里设置
module.exports = {
  mode: 'production'
}; 
//2.参数启动,如果参数启动 后续在配置修改,依然会被这里覆盖,容易混乱
webpack --mode=production

设置后的效果

mode: 'develop' 
//等价于
module.exports = {
     mode: 'development',
     plugins: [
     new webpack.NamedModulesPlugin(),
    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
     ]
    }
//`development`会将 `DefinePlugin` 中 `process.env.NODE_ENV` 的值设置为 `development`。
//启用 `NamedChunksPlugin` 和 `NamedModulesPlugin`    

mode: 'production' 
//等价于
module.exports = {
    mode: 'production',
    plugins: [
        new UglifyJsPlugin(/* ... */),
        new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
        new webpack.optimize.ModuleConcatenationPlugin(),
        new webpack.NoEmitOnErrorsPlugin()
    ]
}
    
// production | 会将 `process.env.NODE_ENV` 的值设为 `production`。
//启用 `FlagDependencyUsagePlugin`, `FlagIncludedChunksPlugin`, `ModuleConcatenationPlugin`, 
//`NoEmitOnErrorsPlugin`, `OccurrenceOrderPlugin`, `SideEffectsFlagPlugin` 和 `UglifyJsPlugin`. 

loader

webpack默认只知道如何处理js和JSON模块,那么其他格式的模块处理,和处理⽅式就需要loader

  • style-loader //正真引入页面 把下面css-loader的代码生成style标签插入页面
  • css-loader //只是让webpack支持css解析
  • less-loader
  • sass-loader
  • ts-loader //将Ts转换成js
  • babel-loader//转换ES6、7等js新特性语法
  • file-loader//处理图⽚⼦图
  • eslint-loader

moudle

在 Webpack ⾥⼀切皆模块,⼀个模块对应着⼀个⽂件。Webpack 会从配置的 Entry 开始递归找 出所有依赖的模块。

当webpack处理到不认识的模块时,需要在webpack中的module处进⾏配置,当检测到是什么格式的 模块,使⽤什么loader来处理。

module: {
    rules: [
        {
            test: /\.xxx$/,//指定匹配规则
            use: {
                loader: 'xxx-load'//指定使⽤的loader
            }
        }
    ]
}

//样式模块 转化例子
//css-loader 分析css模块之间的关系,并合成⼀个css
//Style-loader 会把css-loader⽣成的内容,以style挂载到⻚⾯的heade部分
//注意执行顺序 是从右往左执行
//npm install style-loader@0.23.1 css-loader@2.1.1 -D
{
    test: /\.css$/,
    use: ["style-loader", "css-loader"]
}


//npm install vue-loader -D
//.vue例子
{
    test: /\.vue$/,
    use: ["vue-loader", "css-loader"]
}

plugins 扩展

webpack的打包过程是有(⽣命周期概念)钩⼦

plugin 可以在webpack运⾏到某个阶段的时候,帮你做⼀些事情,类似于⽣命周期的概念 扩展插件,在 Webpack 构建流程中的特定时机注⼊扩展逻辑来改变构建结果或做你想要的事情。 作⽤于整个构建过程

安装 html-webpack-plugin

npm i -D html-webpack-plugin@3.2.0

例子:

const path = require("path");
const htmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
    ...
    plugins: [
        new htmlWebpackPlugin({
            title: "My App",
            filename: "app.html",
            template: "./src/index.html"
        })
    ]
};

//创建文件
touch index.html
//index.html 下面通过 <%= htmlWebpackPlugin.options.title %>可以取到htmlWebpackPlugin设置的信息
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title><%= htmlWebpackPlugin.options.title %></title>
    </head>
    <body>
        <div id="root"></div>
    </body>
</html>

bundle

资源经过Webpack 流程解析编译后最终结输出的成果⽂件。一般为main.js

chunk

指代码块,⼀个 chunk 可能由多个模块组合⽽成,也⽤于代码合并与分割。

一般一个页面有多个引用js时,一个bundle里面的chunks就会对应多个 module

6.module,chunk 和 bundle区别

安装 mini-css-extract-plugin

npm i mini-css-extract-plugin@0.6.0 -D

首先我们在 src 目录下写我们的业务代码,引入 index.js、utils.js、common.js 和 index.css 这 4 个文件,目录结构如下:

src/
├── index.css
├── index.html # 这个是 HTML 模板代码
├── index.js
├── common.js
└── utils.js

//index.css 写一点儿简单的样式:

body {
    background-color: red;
}

//utils.js 文件写个求平方的工具函数:
export function square(x) {
    return x * x;
}

//common.js 文件写个 log 工具函数:
module.exports = {
  log: (msg) => {
    console.log('hello ', msg)
  }
}

// index.js 文件做一些简单的修改,引入 css 文件和 common.js:
import './index.css';
const { log } = require('./common');
log('webpack');

//webpack 的配置如下:
{
    entry: {
        index: "../src/index.js",
        utils: '../src/utils.js',
    },
    output: {
        filename: "[name].bundle.js", // 输出 index.js 和 utils.js
    },
    module: {
        rules: [
            {
                test: /.css$/,
                use: [
                    MiniCssExtractPlugin.loader, // 创建一个 link 标签
                    'css-loader', // css-loader 负责解析 CSS 代码, 处理 CSS 中的依赖
                ],
            },
        ]
    }
    plugins: [
        // 用 MiniCssExtractPlugin 抽离出 css 文件,以 link 标签的形式引入样式文件
        new MiniCssExtractPlugin({
            filename: 'index.bundle.css' // 输出的 css 文件名为 index.css
        }),
    ]
}

我们运行一下 webpack,看一下打包的结果:

我们可以看出,index.css 和 common.js 在 index.js 中被引入,打包生成的 index.bundle.css 和 index.bundle.js 都属于 chunk 0,utils.js 因为是独立打包的,它生成的 utils.bundle.js 属于 chunk 1。

image.png

总结

modulechunk 和 bundle 其实就是同一份逻辑代码在不同转换场景下的取了三个名字:

  • 我们直接写出来的是 module,自己写的代码,单个文件
  • webpack 处理时是 chunk,chunk会把所有相关引用的文件都合到一个chunk下面
  • 最后生成浏览器可以直接运行的 bundle。其实bundle就是chunk,只是可以用插件把一个chunk拆多个bundle
  • 同⼀个 entry 下触达到的模块组织成⼀个 chunk
  • 异步模块单独组织为⼀个 chunk
  • entry.runtime 单独组织成⼀个 chunk

参考

github.com/mjsong07/we…