初始webpack

483 阅读6分钟

1.完成第一次打包

初始化项目

开始前要保证已经进安装了node且可以正常使用
在项目目录下执行初始化命令

D:\code\study-web>npm init

安装webpack

  • 默认安装最新版本
npm install --save-dev webpack-cli webpack
  • 安装指定版本
npm install --save-dev webpack-cli@3.3.12 webpack@4.44.1

配置文件

node.js配置

"scripts": {
    "webpack": "webpack --config webpack.config.js"
},
  • 配置完成后执行npm run webpack 等价于执行npm run webpack --config webpack.config.js
  • webpack命令的--config参数指定配置文件为webpack.config.js, 如果不指定定默认值就是webpack.config.js
  • 可以根据实际的需要配置多个命令

webpack配置

在项目目录下创建webpack.config.js文件,并写入

// 通过require导入path
const path = require('path');
// 设置需要导出的对象
module.exports = {
    mode:'development',         //默认为线上模式, 这里指定为开发模式
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
    },
};

在src目录下index.js文件引用很多其他js文件,webpack会递归地构建一个依赖关系图 ,其中包含应用程序需要的每个模块,然后将所有这些模块打包成 bundle.js文件输出到dist目录

  • webpack可以打包成多个文件,且名称也可以配置
  • 该文件属于nood.js的模块,
  • 各项配置具体含义请参考webpack核心概念

编译

通过 npm run webpack 命令进行编译

D:\code\study-web>npm run webpack

> study-web@1.0.0 webpack D:\code\study-web
> webpack --config webpack.config.js

Hash: e25fc83c5954c62acd56
Version: webpack 4.44.1
Time: 82ms
Built at: 2021/11/27 下午6:12:59
    Asset     Size  Chunks             Chunk Names
bundle.js  4.5 KiB    main  [emitted]  main
Entrypoint main = bundle.js
[./src/index.js] 65 bytes {main} [built]
[./src/module.js] 47 bytes {main} [built]

image.png

2.核心概念

入口(entry)

进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。 可以通过中配置 entry 属性,来指定一个入口起点(或多个入口起点)。

单入口

  • 方式一:字符串的形式
const config = {
  entry: './path/to/my/entry/file.js'
};
  • 方式二:对象的形式
const config = {
  entry: {
    main: './path/to/my/entry/file.js'
  }
};

上面这两种写法是等价的,两种方式传递给出口的name都为main

出口(output)

单出口

output: {
    path: path.resolve(__dirname, 'dist'),
    filename: ' main.js',
    }

多出口

    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js',
    },

注意:入口的单双必须配合使用

  • 单入口可以对应两种出口模式
  • 多入口只能对应多出口的写法

loader

loader可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理

使用loader的三种方式

在你的应用程序中,有三种使用 loader 的方式:

  • 配置(推荐):在 webpack.config.js 文件中指定 loader。
  • 内联:在每个 import 语句中显式指定 loader。
  • CLI:在 shell 命令中指定它们。

babel-loader的使用

安装babel

Babel 中文文档 Babel 配置文档

  • 默认安装最新版本
npm install --save-dev @babel/core @babel/cli
// 安转指定编译版本的包
npm install @babel/preset-env@ --save-dev
  • 安装指定版本
npm install --save-dev @babel/core@7.11.0 @babel/cli@7.10.5
// 安转指定编译版本的包
npm install @babel/preset-env@7.11.0 --save-dev
  • babel/cli 是用于在命令行使用bable的,如何如果将bable作为loader结合webpack使用可以不安装

安装babel-loader

npm install --save-dev babel-loader@8.1.0

配置文件

  • 配置babel

在项目目录创建.babelrc文件,写入

{
  "presets": ["@babel/preset-env"]
}
  • 配置loader 这里采用loader的第一种使用方式:配置webpack.config.js文件
    module.rules 允许你在 webpack 配置中指定多个 loader。 这是展示 loader 的一种简明方式,并且有助于使代码变得简洁。同时让你对各个 loader 有个全局概览:
// 通过require导入path
const path = require('path');

module.exports = {
    mode: 'development', //默认为线上模式, 这里指定为开发模式
    entry: {
        index: './js/index.js',
        test: './js/test.js',
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js',
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'bable-loader',
            },
        ],
    },
};
  • test: 通过正则匹配需要loader处理的文件
  • exclude: 通过正则匹配不需要loader处理的文件
  • loader: 指定使用哪个loader来处理符合条件为文件

module.rules属性是一个数组中存放了多个对象,其中每一个对象代表一个loader的配置信息。

插件(plugins)

插件 是 webpack 的支柱功能。Webpack 自身也是构建于你在 webpack 配置中用到的 相同的插件系统 之上! 插件目的在于解决loader无法实现的其他事情。Webpack 提供很多开箱即用的 插件

html-webpack-plugin的使用

在这里以常用的插件html-webpack-plugin为例来理解插件改如何使用,我们还可以使用更多插件

安装

npm install --save-dev html-webpack-plugin@4.3.0

配置

  • 导入html-webpack-plugin模块
const HtmlWebpackPlugin = require('html-webpack-plugin');
  • 创建HtmlWebpackPlugin对象
plugins: [
    new HtmlWebpackPlugin({
        template: './search.html',
        filename: 'search.html',
        chunks: ['search'],
        minify: {
            removeComments: true,
            collapseWhitespace: true,
            removeAttributeQuotes: true,
        },
    }),
],
  • template:需要处理的HTML文件的相对路径
  • filename:处理完成后新的文件名称,存放路径为:在出口中配置的path属性
  • chunks:指定该html文件需要引入的js文件,把单个或多个入口的键以字符串的形式放入数组
  • removeComments: 删除html中的注释
  • collapseWhitespace: 删除html中的空格
  • removeAttributeQuotes: 删除html标签属性值的双引号
  • 需要处理多个html文件就在plugins中加入多个HtmlWebpackPlugin对象即可。

html-webpack-plugin插件的更多配置,这里的配置不是通用的,需要根据每个插件的文档进行配置

模式(mode)

webpack有development(开发模式)和production(生产模式)两种处理模式

module.exports = {
  mode: 'production'
};
  • 不配置该项默认为生产模式
  • 初浅的理解
    • 开发模式:实现主要功能的情况下,尽可能让人还能看的懂处理完后的代码,方便排查错误
    • 生产模式:尽可能让代码性能更高,人基本已经很难看懂了
  • 两种模式的本质是开发模式只使用了功能性的plugin,而生产模式还使用了提高代码性能的plugin。详情

总结

由于入口出口写法方式和组合很多、很乱,总结一下:

入口

  • 入口有字符串的写法和对象的写法,字符串的写法只支持单入口,对象写法单入口多入口都可以
  • 入口的写法推荐用方式二便于修改,更灵活

出口

  • 推荐多出口的方式,使用占位符来确保每个文件具有唯一的名称

举例

按照推荐的写法也就是说只需要对入口进行配置就可以了,更多出口配置

const path = require('path');

module.exports = {
   
    entry: {
        index: './js/index.js',
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js',
    },
};

3.实际应用

js

通过babel-loader我们可以可以将es6代码编译为以ECMAScript 2015为标准的js代码 其实只对es6新增的语法进行了处理,对新增的函数和静态方法未进行处理

core-js

通过core-js对es6中的新的函数和静态方法进行处理的包

  • 安装
npm install --save-dev core-js@3.6.5
  • 使用 在入口文件导入core-js/stable
import "core-js/stable";

综合应用

安装包

npm install --save-dev @babel/core@7.11.0
npm install --save-dev @babel/preset-env@7.11.0
npm install --save-dev babel-loader@8.1.0
npm install --save-dev core-js@3.6.5

配置

  • 入口文件导入core-js
import "core-js/stable";
  • webpack配置文件
const path = require('path');

module.exports = {
    mode: 'development', 
    entry: {
        index: './js/index.js',
        test: './js/test.js',
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js',
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
            },
        ],
    },
};

html

综合应用

  • 安装
npm install --save-dev html-webpack-plugin@4.3.0
  • 配置
    • 导入模块
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    • 添加HtmlWebpackPlugin对象
    plugins: [
        new HtmlWebpackPlugin({
            template: './search.html',
            filename: 'search.html',
            chunks: ['search'],
            minify: {
                removeComments: true,
                collapseWhitespace: true,
                removeAttributeQuotes: true,
            },
        }),
    ],
    

css

安装loader

  • css-loader 协助webpack解析需要导入的css文件
npm install --save-dev css-loader@4.1.1
npm install --save-dev style-loader@1.2.1
npm install --save-dev mini-css-extract-plugin@0.9.0
  • style-loader(不推荐) 将引用的css写入HTML的style标签中
  • mini-css-extract-plugin(推荐) 将css作为文件引入

导入css

在入口文件中导入css

import './../css/base.css';
import './../css/cssreset-min.css';
import './../css/stylte.css';

配置文件

// 通过require导入path
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// const { loader } = require('mini-css-extract-plugin');

module.exports = {
    mode: 'development', //默认为线上模式, 这里指定为开发模式
    entry: {
        index: './js/index.js',
        test: './js/test.js',
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js',
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader'],
            },
        ],
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: 'css/[name].css',
        }),
    ],
};

  • css-loader 负责识别入口文件中导入的css文件
  • mini-css-extract-plugin 负责压缩css文件并使用link标签引入html
  • filename:通过改属性指定处理完的css文件存放位置,更多配置

图片

用file-loader来处理css中引入的图片(字体、字体图标)都是可以的

  • file-loader
  • url-loader

安装

npm install --save-dev file-loader@6.0.0
npm install --save-dev url-loader@4.1.0
  • 只对图片进行打包,安装file-loader就行
  • 需要对文件进行转码、设置MIME 类型并打包就两个都装只对url-loader进行配置就可以

个人理解url-loader是基于file-loader的基础上做了一些扩展,所以两个都需要安装并对url-loader进行配置就可以

配置

{
    test: /\.(png|jpg|gif)$/,
    use: [
        {
            loader: 'url-loader',
            options: {
                name: '[name].[ext]',
                outputPath: 'img/',
                limit: 8192,     
                esModule: false, // 不启用js模块语法
            },
        },
    ],
},
  • name:属性指定指定出后文件的名称,name、ext属于占位符。更多占位符
  • outputPath:指定处理后的图片保存位置(相对于出口设置的位置)
  • limit:指定文件是否进行base64转码,默认值true,当为数值时单位为B,为0时等价于false
  • esModule:是否启用模块语法
  • options:更多配置 同一个对象中存在如下冲突
  • 使用options属性时不能使用use属性
  • 使用options属性时loader属性的不能为数组

css中引入图片的处理

css引用图片路径不正确
由于图片由file-loader放在了指定路径下,需要调整css中引用图片的设置

css相关的处理由mini-css-extract-plugin处理,做如下调整:

{
    test: /\.css$/,
    use: [
        {
            loader: MiniCssExtractPlugin.loader,
            options: {
                publicPath: '../',
            },
        },
        'css-loader',
    ],
    },

html中引入的图片

使用html-withimg-loader识别这部分图片,由url-loader对这部分图片进行打包或base64转码

安装

npm install --save-dev html-withimg-loader@0.1.16

配置

// 处理Html文件
{
    test: /\.(html|htm)$/,
    loader: 'html-withimg-loader',
},

此时处理完成后img标签的src属性被设置为了对象

需要修改url-loader配置esModule为false解决此问题

{
    test: /\.(png|jpg|gif)$/,
    use: [
        {
            loader: 'url-loader',
            options: {
                name: '[name].[ext]',
                outputPath: 'img/',
                limit: 8192,         
                esModule: false, 
            },
        },
    ],
},

字体图标文件

通过url-loader打包

配置

{
    test: /\.(ttf|woff|woff2)$/,
    use: [
        {
            loader: 'url-loader',
            options: {
                limit: 8192,
                name: '[name].[ext]',
                outputPath: 'fonts/',
            },
        },
    ],
},

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
    mode: 'development', //默认为线上模式, 这里指定为开发模式
    entry: {
        index: './js/index.js',
        test: './js/test.js',
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js',
    },
    module: {
        rules: [
            // 处理js文件
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: ['babel-loader'],
            },
            // 处理css文件
            {
                test: /\.css$/,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader,
                        options: {
                            publicPath: '../',
                        },
                    },
                    'css-loader',
                ],
            },
            // 处理Html文件
            {
                test: /\.(html|htm)$/,
                loader: 'html-withimg-loader',
            },
            // 处理图片
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            name: '[name].[ext]',
                            outputPath: 'img/',
                            limit: 8192, //指定是否进行base64转
                            esModule: false, // 不以es6模块的形式导出
                        },
                    },
                ],
            },
            // 处理字体、图标
            {
                test: /\.(ttf|woff|woff2)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,
                            name: '[name].[ext]',
                            outputPath: 'fonts/',
                        },
                    },
                ],
            },
        ],
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './index.html',
            filename: 'index.html',
            chunks: ['index'],
        }),
        new HtmlWebpackPlugin({
            template: './test.html',
            filename: 'good.html',
            chunks: ['test', 'index'],
        }),
        new MiniCssExtractPlugin({
            filename: 'css/[name].css',
        }),
    ],
};

4.搭建开发环境

通过webpack-dev-server的来实现类似于vscode中live-server插件的效果

安装

npm install --save-dev webpack-dev-server@3.11.0

配置

启动命令配置

"scripts": {
    "webpack": "webpack --config webpack.config.js",
    "dev": "webpack-dev-server --open chrome"
},

webpack配置