webpack打包练习与思考

一、简答题

1、Webpack 的构建流程主要有哪些环节?如果可以请尽可能详尽的描述 Webpack 打包的整个过程。

主要环节

  • 安装webpack ,yarn add webpack@4.44.2 webpack-cli@3.3.3 -D

  • 配置webpack.config.js文件

  • 在webpack.config.js中配置entry, output以及mode

  • 根据要加载的文件类型,安装配置不同的loader加载器

  • 根据项目的需求,实现非loader的功能,安装相应的plugins

  • 配置devserver 开启自动化编译和浏览器预览

  • 配置optimization 进行项目优化等等操作。

2、Loader 和 Plugin 有哪些不同?请描述一下开发 Loader 和 Plugin 的思路。

Loader与Plugin的区别:

webpack只能识别javascript和json文件,而loader能够让webpack去处理更多类型的文件,让他们转换成有效的模块,形成依赖树。

Plugin插件就是处理除了loader转换模块之外的任务,比如打包优化、资源管理

Loader实现思路:

  • module.exports导出一个function接收形参source

  • 处理source文件

  • 返回一个js字符串

Plugins实现思路:

  • 导出一个插件类,在类的原型上定义apply方法

  • webpack初始化完成,apply方法上接收compiler对象

  • 通过compiler对象的钩子,定义在某个阶段注入插件,通过tabable定义钩子的触发方式

  • tabable中的方法接受插件名和一个函数,这个函数中接受compliation对象

  • 通过compliation对象上的属性,执行自己想要实现的功能,比如资源类的assets

  • 最后将处理后的结果给compliation上assets属性重新赋值

二、编程题

1、使用 Webpack 实现 Vue 项目打包任务 具体任务及说明:

说明:

  1. 安装和配置eslint
  • 删除package中的eslint相关的配置.

  • yarn add eslint ,然后运行eslint --init 初始化 .eslintrc.js ,根据提示安装响应的包

yarn add eslint-plugin-vue@latest eslint-config-standard@latest eslint@^7.12.1 eslint-plugin-import@^2.22.1 eslint-plugin-node@^11.1.0 eslint-plugin-promise@^4.2.1 -D
  1. 安装和配置prettier
  • 安装
yarn add prettier @vue/eslint-config-prettier eslint-plugin-prettier -D
  • 在.eslintrc.js中添加
module.exports = {

  extends: [
    ...
    '@vue/prettier'
  ],

}
  • 新建.prettierrc.js文件
// prettier.config.js or .prettierrc.js
module.exports = {
  trailingComma: "es5",
  tabWidth: 4,
  semi: false,
  singleQuote: true
};
  1. 安装和配置lint-stage和husky
  • 安装
yarn add lint-staged husky -D
  • 在package.json中添加
{
  "scripts": {
     "lint-staged:js": "eslint --ext .js,.vue,.ts",
    "lint:fix": "eslint --fix --cache --ext .js,.vue,.ts --format=pretty ./src",
    "lint:js": "eslint --cache --ext .js,.vue,.ts,--format=pretty ./src",
    "lint:prettier": "prettier --check \"src/**/*\" --end-of-line auto",
    "precommit": "lint-staged",
  },

  "lint-staged": {
    "**/*.{js,vue,ts,less,md,json}": [
      "prettier --write",
      "npm run lint:js",
      "git add"
    ]
  },
}
  1. 安装webpack
yarn add webpack@4.44.2 webpack-cli@3.3.3 -D
  1. 安装webpack-merge,配置多环境
yarn add webpack-merge -D

webpack.common.js中

module.exports = {
  entry: "./src/main.js",
  output: {},
};

webpack.dev.js中

const common = require("./webpack.common");
const { merge } = require("webpack-merge");
module.exports = merge(common, {
  mode: "development",
});
});

webpack.prod.js中

const common = require("./webpack.common");
const { merge } = require("webpack-merge");
module.exports = merge(common, {
  mode: "production",
});

});
  1. 在webpack.common.js中配置打包入口和输出
const path = require("path");
module.exports = {
  entry: "./src/main.js",
  output: {
    filenaem: "[name].[contenthash].js",
    path: path.resolve(__dirname, "dist"),
  },
};
};
  1. 在package.json中配置build命令
{
   "scripts": {
    "build": "webpack --config webpack.prod.js",
  },
}

运行 yarn build命令 之后提示如下,

在这里插入图片描述

  1. 解析.vue结尾的文件
  • 安装
yarn add vue-loader  vue-template-compiler -D
  • 在webpack.common.js中
const VueLoaderPlugin = require("vue-loader/lib/plugin");
module.exports = {

 module: {
    rules: [
      {
        test: /\.vue$/,
        use: ["vue-loader"],
      },
    ],
  },
  plugins: [new VueLoaderPlugin()],
}
  1. 解析.css文件和.less文件
  • 安装
yarn add css-loader style-loader -D
  • webpack.common.js中
module.exports = {
 module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader"],
      },
    ],
  },
}
  1. 解析图片资源文件
  • 安装
yarn add url-loader file-loader -D
  • webpack.common.js中
module.exports = {

  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|webp)(\?.*)?$/i,
        use: [
          {
            loader: "url-loader",
            options: {
              limit: 4096,
              fallback: "file-loader",
               esModule: false,
            },
          },
        ],
      },
    ],
  },
};
  1. 解析.js文件
  • 安装
yarn add babel-loader @babel/core @babel/preset-env @vue/cli-plugin-babel eslint-loader -D
  • webpack.common.js中
module.exports = {
       module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-env'],
                        },
                    },
                    'eslint-loader',
                ],
            },
        ],
    },
}
  1. CleanWebpackPlugin、ProgressPlugin、HtmlWebpckPlugin

CleanWebpackPlugin每次构建前清除目标目录

HtmlWebpckPlugin根据index.html模板生成html文件

ProgressPlugin显示webpack构建的进度

  • 安装
yarn add clean-webpack-plugin html-webpack-plugin -D
  • webpack.prod.js中
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const webpack = require('webpack')
module.exports = merge(common, {
    mode: 'production',
    plugins: [
        new webpack.ProgressPlugin(),
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: 'vue-app-base',
            template: 'public/index.html',
        }),
    ],
})
}

执行yarn build 出现BASE_URl is not defined

这个错误出现的原因是因为public下面的index.html存在一个全局变量的BASE_URL这个时候需要用DefinePlugin定义全局变量

webpack.prod.js中添加如下

module.exports = merge(common, {

    plugins: [
        new webpack.DefinePlugin({
            BASE_URL: JSON.stringify('/'),
        }),
       .....
    ],
})
  1. 复制public中文件到dist目录中
  • 安装
yarn add copy-plugin-webpack@5.1.2 -D
  • webpack.prod.js中
const path = require('path')
const CopyPlugin = require('copy-webpack-plugin')

module.exports = {
    plugins: [
    new CopyPlugin([
            {
                from: path.join(__dirname, 'public'),
                to: path.join(__dirname, 'dist'),
                ignore: [
                    '.DS_Store',
                    {
                        glob: 'index.html',
                        matchBase: false,
                    },
                ],
            },
        ]),
    ]
}
  1. 开启server并自动编译
  • 安装
yarn add webpack-dev-server -D
  • webpack.dev.js中
module.exports = {
 devServer: {
        contentBase: path.join(__dirname, 'public'),
        compress: true,
        open: true,
        port: 9000,
    },
}
  • package.json中配置
{
   "scripts": {
    "serve": "webpack-dev-server --config webpack.dev.js --watch",
  },
}
  1. 配置打包优化
  • 安装
yarn add terser-webpack-plugin -D
  • webpack.prod.js中
module.exports = {
    optimization: {
        minimize: true,
        minimizer: [
            new TerserWebpackPlugin({
                cache: true,
                parallel: true,
                sourceMap: true,
            }),
        ],
        splitChunks: {
            chunks: 'all',
            minChunks: 1,

            cacheGroups: {
                vendors: {
                    name: 'chunk-vendors',
                    test: /[\\/]node_modules[\\/]/,
                    priority: -10,
                    chunks: 'all',
                },
                common: {
                    name: 'chunk-common',
                    minChunks: 2,
                    chunks: 'initial',
                    priority: -20,
                },
            },
        },
        runtimeChunk: {
            name: (entrypoint) => `runtimechunk~${entrypoint.name}`,
        },
    },
}
  1. 最后调整开发和生产的配置,如下

webpack.common.js

const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    entry: './src/main.js',
    output: {
        filename: '[name].[contenthash].js',
        path: path.resolve(__dirname, 'dist'),
    },

    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-env'],
                        },
                    },
                    'eslint-loader',
                ],
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            },
            {
                test: /\.less$/,
                use: ['style-loader', 'css-loader', 'less-loader'],
            },
            {
                test: /\.vue$/,
                use: ['vue-loader'],
            },
            {
                test: /\.(png|jpe?g|gif|webp)(\?.*)?$/i,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 4 * 1024,
                            fallback: 'file-loader',
                            esModule: false,
                        },
                    },
                ],
            },
        ],
    },
    plugins: [
        new VueLoaderPlugin(),
        new webpack.DefinePlugin({
            BASE_URL: JSON.stringify('/'),
        }),
        new webpack.ProgressPlugin(),
        new HtmlWebpackPlugin({
            title: 'vue-app-base',
            template: 'public/index.html',
        }),
    ],
}

webpack.dev.js

const path = require('path')
const common = require('./webpack.common')
const { merge } = require('webpack-merge')
module.exports = merge(common, {
    mode: 'development',
    devtool: 'cheap-module-eval-source-map',
    devServer: {
        contentBase: path.join(__dirname, 'public'),
        compress: true,
        open: true,
        port: 9000,
    },
})

webpack.prod.js

const common = require('./webpack.common')
const { merge } = require('webpack-merge')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyPlugin = require('copy-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')
const path = require('path')
module.exports = merge(common, {
    mode: 'production',
    optimization: {
        minimize: true,
        minimizer: [
            new TerserWebpackPlugin({
                cache: true,
                parallel: true,
                sourceMap: true,
            }),
        ],
        splitChunks: {
            chunks: 'all',
            minChunks: 1,

            cacheGroups: {
                vendors: {
                    name: 'chunk-vendors',
                    test: /[\\/]node_modules[\\/]/,
                    priority: -10,
                    chunks: 'all',
                },
                common: {
                    name: 'chunk-common',
                    minChunks: 2,
                    chunks: 'initial',
                    priority: -20,
                },
            },
        },
        runtimeChunk: {
            name: (entrypoint) => `runtimechunk~${entrypoint.name}`,
        },
    },
    plugins: [
        new CleanWebpackPlugin(),

        new CopyPlugin([
            {
                from: path.join(__dirname, 'public'),
                to: path.join(__dirname, 'dist'),
                ignore: [
                    '.DS_Store',
                    {
                        glob: 'index.html',
                        matchBase: false,
                    },
                ],
            },
        ]),
    ],
})

先下载任务的基础代码 百度网盘链接: https://pan.baidu.com/s/1pJl4k5KgyhD2xo8FZIms8Q 提取码: zrdd

这是一个使用 Vue CLI 创建出来的 Vue 项目基础结构

有所不同的是这里我移除掉了 vue-cli-service(包含 webpack 等工具的黑盒工具)

这里的要求就是直接使用 webpack 以及你所了解的周边工具、Loader、Plugin 还原这个项目的打包任务

尽可能的使用上所有你了解到的功能和特性

作业要求

本次作业中的编程题要求大家完成相应代码后(二选一)

  1. 简单录制一个小视频介绍一下实现思路,并演示一下相关功能。

  2. 提交一个项目说明文档,要求思路流程清晰。

最终将录制的视频或说明文档和代码统一提交至作业仓库。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值