likes
comments
collection
share

webpack5零基础搭建

作者站长头像
站长
· 阅读数 16

在平时工作项目中,我们一般都会使用webpack或者vite去构建项目。很多小白却不理解webpack到底有什么作用。

1.作用

webpack能将我们项目中的es6、less、scss等浏览器不识别的语言转换成浏览器能识别的语言,不同的loader能处理不同类型的文件。

2.组成

2.1 入口文件-entry

告诉webpack从哪个文件开始上手去构建内部依赖图,默认值是./src/index.js

2.2 输出-output

告诉webpack它创建好的bundle应该输出到哪里去,以及应该如何命名这些文件。默认值为 ./dist/main.js。其他生成文件默认放到dist文件夹

2.3 模式-mode

不同的环境设置不同的值。development为开发环境,production为生产环境。

2.4 插件-plugin

是一种可扩展的机制,可以在打包过程中添加其他的额外功能,如打包分析BundleAnalyzerPlugin,css提取MiniCssExtractPlugin

2.5 module

loader配置

3.文件创建

3.1、初始化package.json文件

运行yarn init初始化一个package.json文件

yarn init

3.2、安装依赖

为了快速步入正轨,我先把要安装的包先提供出来。

{
  "name": "webpack5-demo",
  "version": "1.1.0",
  "description": "webpack5 Demo",
  "main": "index.js",
  "scripts": {
    "start": "node scripts/start.js -hot",
    "build": "webpack --config webpack.prod.js"
  },
  "repository": {
    "type": "git",
    "url": ""
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "homepage": "",
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@swc/core": "^1.3.53",
    "@types/react": "^18.0.38",
    "@types/react-dom": "^18.0.11",
    "browserslist": "^4.21.5",
    "css-loader": "^6.7.3",
    "css-minimizer-webpack-plugin": "^5.0.0",
    "html-webpack-plugin": "^5.5.1",
    "less": "^4.1.3",
    "less-loader": "^11.1.0",
    "mini-css-extract-plugin": "^2.7.5",
    "path": "^0.12.7",
    "postcss": "^8.4.23",
    "postcss-loader": "^7.2.4",
    "resolve-url-loader": "^5.0.0",
    "style-loader": "^3.3.2",
    "swc-loader": "^0.2.3",
    "terser-webpack-plugin": "^5.3.7",
    "typescript": "^5.0.4",
    "webpack": "^5.80.0",
    "webpack-bundle-analyzer": "^4.8.0",
    "webpack-cli": "^5.0.2",
    "webpack-dev-server": "^4.13.3",
    "webpack-manifest-plugin": "^5.0.0",
    "webpack-merge": "^5.8.0",
    "react-dev-utils": "^12.0.0"
  }
}

3.2 新增文件

新建一个webpack.dev.js文件,webpack.prod.js文件,新建一个src文件夹,src目录下新增index.tsx,app.tsx,app.less。目录结构如下

-public
  -index.html
-src
  -index.tsx
  -App.tsx
  -app.less
-webpack.dev.js
-webpack.prod.js

index.tsx

import React from 'react';

import App from './App';
import { createRoot } from 'react-dom/client';

const root = createRoot(document.getElementById('root') as Element);
root.render(<App />);

App.tsx

import React from 'react';
import './app.less';
import icon from './pig.jpeg';
const App = () => {
  return (
    <div className="test">
      <div className="img"></div>
      <img src={icon} alt="" />
      demo测试
    </div>
  );
};

export default App;

app.less

.test {
  color: red;
  .img {
    background-image: url('./pig.jpeg');
    width: 200px;
    height: 200px;
    background-size: contain;
  }
  img {
    width: 100px;
    height: 100px;
  }
}

public/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

到此,我们文件夹就创建完成了。

4.webpack配置

webpack有两个配置文件,一个是开发环境的配置文件(webpack.dev.js),用于开发环境的编译(webpack.prod.js),一个是生产环境的配置文件,用于生产环境的打包构建。因为它们的大部分配置都差不多,所以可以抽离一个公共的方法供两个文件使用,这里我们命名为webpack.base.js

4.1 webpack.base.js

入口文件配置entry

 entry: './src/index.tsx',

输出目录配置output

output: {
  filename: 'js/main.[contenthash:8].js',
  clean: true, // 每次build清除上一次build的目录,重新生成新的hash文件
},

编译代码环境target,如果想在类Node.js 环境编译代码,则target字段配置为node,默认值就是‘web’

target: 'web',

模块解析resolve,根据项目文件扩展名灵活配置。

resolve: {
  extensions: ['.tsx', '.js', '.json', '.ts', '.jsx'],
},

处理项目各个模块module。这里没有使用babel-loader,因为swc-loader编译速度更快。 注意:css分离需要用MiniCssExtractPlugin.loader取代style-loader,这些css资源会在 HTML 文件 <head> 元素中的 <link> 标签内引入。

module: {
      rules: [
        {
          test: [/\.gif$/, /\.jpe?g$/, /\.png$/],
          type: 'asset',
          parser: {
            dataUrlCondition: {
              maxSize: 1024,
            },
          },
        },
        {
          test: /\.(jsx|js|ts|tsx)?$/,
          // 官方SWC的编译速度相对于Babel可提升近20倍
          use: ['swc-loader'],
          include: path.resolve(__dirname, 'src'),
        },
        {
          test: /\.css$/,
          use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
        },
        {
          test: /\.less$/,
          use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader'],
        },
      ],
    },

plugin,解决loader无法实现的其他事情。例如HtmlWebpackPlugin 生成html文件,在 body 中使用 script 标签引入你所有 webpack 生成的 bundle。

plugins: [
  new HtmlWebpackPlugin({
    filename: 'index.html',
    template: './public/index.html',
  }),
],

到这里webpack.base.js的简易配置就完成了,完整代码如下

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

module.exports = () => {
  return {
    entry: './src/index.tsx',
    output: {
      filename: 'js/main.[contenthash:8].js',
      clean: true, // 每次build清除上一次build的目录,重新生成新的hash文件
      assetModuleFilename: 'images/[hash:8][ext][query]',  // 指定图片资源输出目录
      path: path.resolve(__dirname, 'build'),
    },
    target: 'web',
    resolve: {
      extensions: ['.tsx', '.js', '.json', '.ts', '.jsx'],
    },
    module: {
      rules: [
        // 处理图片资源
        // webpack5 提供了一个新特性叫作 Asset Modules,在内部实现了对资源模块的支持。Asset Modules 提供了4种资源模块的类型,无需再额外配置其他的loader来对资源模块进行处理。详情见https://webpack.docschina.org/guides/asset-modules/
        {
          test: [/\.gif$/, /\.jpe?g$/, /\.png$/],
          type: 'asset',
          parser: {
            dataUrlCondition: {
              maxSize: 1024,
            },
          },
        },
        {
          test: /\.(jsx|js|ts|tsx)?$/,
          // 官方SWC的编译速度相对于Babel可提升近20倍
          use: ['swc-loader'],
          include: path.resolve(__dirname, 'src'),
        },
        {
          test: /\.css$/,
          // 为了让css分离,必须用MiniCssExtractPlugin.loader替代style-loader
          use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
        },
        {
          test: /\.less$/,
          use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader'],
        },
      ],
    },
    plugins: [
      new HtmlWebpackPlugin({
        filename: 'index.html',
        template: './public/index.html',
      }),
    ],
  };
};

4.2 webpack.dev.js

在webpack.dev.js可以通过merge来合并webpack.base.js的配置。然后新增一些其他配置。

const base = require('./webpack.base.js');
const { merge } = require('webpack-merge');

module.exports = () => {
  return merge(base(), {
    ...
  });
};

配置mode模式

mode: development

使用MiniCssExtractPlugin插件实现css分离。

const base = require('./webpack.base.js');
const { merge } = require('webpack-merge');

module.exports = () => {
  return merge(base(), {
    ...,
    plugins: [
      new MiniCssExtractPlugin({
        filename: 'css/[contenthash:8].css',
      }),
    ]
  });
};

devServer配置端口号,gzips压缩等。

const base = require('./webpack.base.js');
const { merge } = require('webpack-merge');

module.exports = () => {
  return merge(base(), {
    ...,
    devServer: {
      port: 3000,
      watchFiles: {
        options: {
          aggregateTimeout: 200,
          ignored: ['**/public','**/node_modules'],
        },
      },
      compress: true,
    },
  });
};

stats配置控制台打印信息。因为本人不喜欢控制台显示过多无用信息,就去掉了大部分显示

const base = require('./webpack.base.js');
const { merge } = require('webpack-merge');

module.exports = () => {
  return merge(base(), {
    ...,
    stats: {
      assets: false, // 是否展示资源信息
      entrypoints: false, // 是否展示入口文件与对应的文件 bundles。
      modules: false, // 是否添加关于构建模块的信息。
    },
  });
};

到此,webpack.dev.js的简易配置就差不多完成了,完整代码如下:

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const base = require('./webpack.base.js');

const { merge } = require('webpack-merge');
module.exports = () => {
  return merge(base(), {
    mode: 'development',
    plugins: [
      new MiniCssExtractPlugin({
        filename: 'css/[contenthash:8].css',
      }),
    ],
    devServer: {
      port: 3000,
      watchFiles: {
        options: {
          aggregateTimeout: 200,
          ignored: ['**/public'],
        },
      },
      compress: true,
      client: {
        progress: true,
      },
    },
    stats: {
      assets: false, // 是否展示资源信息
      entrypoints: false, // 是否展示入口文件与对应的文件 bundles。
      modules: false, // 是否添加关于构建模块的信息。
    },
  });
};

执行yarn start,可以看到启动完成。

webpack5零基础搭建

4.3 webpack.prod.js

webpack.prod.js配置和webpack.dev.js的配置大差不差,注意的是webpack.prod.js的 mode应该为production,代表生产模式的环境。webpack.dev.js的mode是development,代表开发环境。

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const base = require('./webpack.base.js');
const { merge } = require('webpack-merge');
module.exports = env => {
  return merge(base(env), {
    mode: 'production',
    plugins: [
      new MiniCssExtractPlugin({
        filename: 'css/[name].[contenthash:8].css',
      }),
    ],
  });
};

BundleAnalyzerPlugin打包分析插件

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

const { merge } = require('webpack-merge');
module.exports = env => {
  return merge(base(env), {
    ...
    plugins: [
      // 打包分析
      new BundleAnalyzerPlugin(),
     ...
    ],
  });
};

执行build命令后会生成如下图,可以查看每个资源的体积大小。如果哪个资源体积比较大,后续可以做优化处理。 webpack5零基础搭建

css压缩css-minimizer-webpack-plugin

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

const { merge } = require('webpack-merge');
module.exports = env => {
  return merge(base(env), {
    ...
    
    optimization: {
      minimize: true,
      minimizer: [
        // css压缩
        new CssMinimizerPlugin(),
      ],
    },
  });
};

js压缩terser-webpack-plugin。注意:生产环境会默认配置terser-webpack-plugin,所以这个插件也可以不用配置

 const TerserPlugin = require('terser-webpack-plugin');

const { merge } = require('webpack-merge');
module.exports = env => {
  return merge(base(env), {
    ...
    
    optimization: {
      minimize: true,  // 告知 webpack 使用 TerserPlugin 或其它在 optimization.minimizer定义的插件压缩 bundle。
      minimizer: [
        // js压缩
        new TerserPlugin(),
      ],
    },
  });
};

4.4 自定义配置启动时的相关输出信息

虽然一般情况都是建议通过cli运行webpack-dev-server,但是我们也可以选择通过api启动服务器。

修改package.json的启动命令

"scripts": {
    "start": "node scripts/start.js",
     ...
  },

新建scripts目录并且在此目录下新建一个start.js文件,代码如下:

'use strict';
const Webpack = require('webpack');
const chalk = require('react-dev-utils/chalk');
const WebpackDevServer = require('webpack-dev-server');
const webpackConfig = require('../webpack.dev');
const clearConsole = require('react-dev-utils/clearConsole');

const compiler = Webpack(webpackConfig());
const devServerOptions = { ...webpackConfig().devServer, open: false };
const server = new WebpackDevServer(devServerOptions, compiler);
server.startCallback(() => {
  clearConsole(); // 去掉打印
  console.log(chalk.green('Starting server on http://localhost:3000'));
});

执行yarn start

webpack5零基础搭建 控制台看着确实清爽了不少。

webpack5零基础搭建

这就是最终运行出来的效果

webpack5的大致功能就先分享到这里,如果大家还想了解更多的功能可以去官网多看看webpack.docschina.org/。

想要查看完整项目,请移步仓库地址仓库地址:github.com/red-pen/web…