从0-1 webpack 手动搭建项目

从0-1 webpack 手动搭建项目

1. 安装 npm 包

npm install webpack-cli webpack -D

2. 在指定文件夹下面创建配置文件

我们可以在根目录,或者自己想放的目录(eg: /config)下,创建对应的配置文件

我们可以写三个配置文件以便区分环境等

# at /config 
touch webpack.common.js
touch webpack.dev.js
touch webpack.prod.js
复制代码

2.5 全部进行es module 配置(非必须,可选)

package.json中配置属性type的值为module,来指定所有的js文件都用es module 进行解析。

# package.json
{
"type": "module" 
}
复制代码

这里要注意,如果我们使用es module的话, 是不支持__dirname__filename的。 我们查找文件定义时的地址,可以直接用import.meta.url(为当前文件的地址),并用 url模块中的URL来生拼接成想要的内容,而不用再使用__dirname__filename等 例如:

import { URL } from 'url'
export default {
  entry: {
    // index: path.join(__dirname, "../src/index.js")
    index: new URL('../src/index.js', import.meta.url).pathname,
  },
  output: {
    filename: '[name].[contenthash:4].js',
    // path: path.join(__dirname, '../dist') // distribution 发行版
    path: new URL('../dist/', import.meta.url).pathname,
  }
}

复制代码

3. 配置scripts相关包

在配置完后由于我们要合并配置文件夹,同时可能项目需要在不同平台上启动,我们可以安装下面两个工具包

npm install webpack-merge cross-env -D
复制代码

webpack-merge是用来合并配置文件

cross-env用来处理命令行中的不同平台系统的兼容问题

4. 使用配置内容生成HTML文件

先安装html-webpack-plugin来处理生成 html文件

npm install html-webpack-plugin -D

同时为了开发调试能自动启动服务器,我们可以使用

npm install webpack-dev-server -D

来处理本地服务的问题

5. 支持前端框架,react为例

先引用包

npm install react react-dom -S

配置编译工具

npm install babel-loader @babel/core @babel/preset-react -D

// .babelrc 文件
{
	"presets": ["@babel/preset-react"] // preset 是官方配置好的plugins集合,另外配置了一些options
}
复制代码
// webpack.common.js 配置文件
module: {
		rules: [
			{
				test: /\.(js|jsx)$/,
				loader: 'babel-loader'
			}
		]
	}
复制代码

6. 支持ts

npm i @babel/preset-typescript -D

// .babelrc 文件
{
	"presets": ["@babel/preset-react", "@babel/preset-typescript"]// preset 是官方配置好的plugins集合,另外配置了一些options
}
复制代码
	module: {
		rules: [
			{
				test: /\.(js|jsx|ts|tsx)$/, // 增加ts类型支持
				loader: 'babel-loader'
			}
		]
	}
复制代码

7. 支持css和预处理器

npm i style-loader css-loader sass sass-loader less less-loader

	module: {
		rules: [
			{
				test: /\.(js|jsx|ts|tsx)$/,
				loader: 'babel-loader'
			},
			{
				test: /\.css$/,
				use:['style-loader','css-loader']
			},
      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader'],
			{
				test: /\.(sass|scss)$/,
				use:['style-loader','css-loader', 'sass-loader']
			}
		]
	}
复制代码

在这里要注意如果引入一个loader, 我们直接写 lodader,如果要引入多个,使用use, 并且use数组中的loader的执行顺序是从右到左执行的(类似于每次pop出一个loader执行)。

8.支持img引入等

npm install url-loader file-loader -D

  module: {
    rules: [
      {
        test: /\.(js|jsx|ts|tsx)$/,
        loader: 'babel-loader',
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader'],
      },
      {
        test: /\.(sass|scss)$/,
        use: ['style-loader', 'css-loader', 'sass-loader'],
      },
      {
        test: /\.(png|jpg|gif|jpeg)$/,
        use: [{ loader: 'url-loader', options: { limit: +10240 } }],
      },
      { test: /\.(woff|woff2|eot|ttf|otf)$/, use: 'file-loader' },
    ],
  }
复制代码

其中 file-loaderurl-loader的区别

file-loader 用来解析图片和字体

url-loader 也可以用来处理图片和字体,还可以设置较小资源自动 base64

9. 支持 antd

npm install antd -S

如果我们引入了antd/dist/antd.less会报错误,刚刚不是已经处理过less的编译了吗?为什么还会报错呢?

先不着急,我们看看报错的说明

image-20220321080946464.png 这是提示我们在less文件中不支持javascript语法。我们需要在less-loader中进行配置使其支持js

      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader', {
					loader: 'less-loader',
					options: {
						lessOptions: {
							javascriptEnabled: true
						}
					}
				}],
      },
复制代码

关于javscriptEnabled disprecated回答

10. 美化:给Terminal编译过程加个进度条

npm i webpackbar -D

webpackbar是一个plugin, 可以用来显示编译打包进度。

// webpack.dev.config
plugins: [new Webpackbar()],
复制代码

webpackbar

11. 优化

external优化

externals 配置选项提供了「从输出的 bundle 中排除依赖」的方法。相反,所创建的 bundle 依赖于那些存在于用户环境(consumer's environment)中的依赖。此功能通常对 library 开发人员来说是最有用的,然而也会有各种各样的应用程序用到它。

external 能防止将某些 import 的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies)

我们可以从CDN引入react,react-dom,而不是打包。

  externals: {
    // 外部扩展
    react: 'React',
    'react-dom': 'ReactDOM',
  },
复制代码

这样可以很好地优化打包的时间

external

stats 对象

stats 选项让你更精确地控制 bundle 信息该怎么显示。如果只是想要获取某部分 bundle 的信息,使用 stats 选项是比较好的折衷方式。

stats.modules : 告知 stats 是否添加关于构建模块的信息。默认为true

stats

TerserWebpackPlugin

该插件使用 terser 来压缩 JavaScript。

webpack v5 开箱即带有最新版本的 terser-webpack-plugin。如果你使用的是 webpack v5 或更高版本,同时希望自定义配置,那么仍需要安装 terser-webpack-plugin。如果使用 webpack v4,则必须安装 terser-webpack-plugin v4 的版本。

npm install terser-webpack-plugin esbuild --save-dev

  optimization: {
		minimizer: [
			new TersetWebpackPlugin({
				extractComments:false,
				minify: TersetWebpackPlugin.esbuildMinify // esbuild 提速
			}),
		]
	},
复制代码

TerserWebpackPlugin

css-mini-extract-plugin

这个插件将 CSS 提取到单独的文件中。它为每个包含 CSS 的 JS 文件创建一个 CSS 文件。它支持 CSS 和 sourcemap 的按需加载。只在webpack v5及以后版本支持。

npm i mini-css-extract-plugin -D

用法不再赘述,直接看文档

mini-css-extract-plugin

clean-webpack-plugin

A webpack plugin to remove/clean your build folder(s).

const webpackConfig = {
    plugins: [
        /**
         * All files inside webpack's output.path directory will be removed once, but the
         * directory itself will not be. If using webpack 4+'s default configuration,
         * everything under <PROJECT_DIR>/dist/ will be removed.
         * Use cleanOnceBeforeBuildPatterns to override this behavior.
         *
         * During rebuilds, all webpack assets that are not used anymore
         * will be removed automatically.
         *
         * See `Options and Defaults` for information
         */
        new CleanWebpackPlugin(),
    ],
};
复制代码

npm i clean-webpack-plugin -D

clean-webpack-plugin

css-minimizer-webpack-plugin

This plugin uses cssnano to optimize and minify your CSS.

npm i css-minimizer-webpack-plugin -D

css-minimizer-webpack-plugin

happyPack

由于 JavaScript 是单线程模型,我们可以通过使用多进程,启用多核 CPU 的能力。happyPack的思想是使用多个子进程去解析和编译JS,css,等,这样就可以并行处理多个子任务,多个子任务完成后,再将结果发到主进程中

npm install happypack -D

1. 创建 happypack 插件实例
// webpack.common.js
// import HappyPack from 'happypack'
// import os from 'os'
// const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length})

  plugins: [
    new HappyPack({
      id: 'babel', // 唯一标识id, 表示当前实例,后面会在 module/rules中进行使用
      loaders: ['babel-loader?cacheDirectory'], // 和module/rules中的 Loader用法一致
      threads: 3, // 代表开启几个子进程去处理这一类型的文件,默认是3个,类型必须是整数。
      threadPool: happyThreadPool, //  // 使用共享进程池中的子进程去处理任务
    }),
  ],
复制代码
2. 在 Loder中使用
module.exports = {
  module: {
    rules: [
      {
        test: /\.(js|jsx|ts|tsx)$/,
        // loader: 'babel-loader',
        // 在 Loader 配置中,所有文件的处理都交给了 happypack/loader 去处理,使用紧跟其后的 querystring ?id=babel 去告诉 happypack/loader 去选择哪个 HappyPack 实例去处理文件。
        use: ['happypack/loader?id=babel'],
        exclude: /node_modules/,
      },
    ]
  },
}
复制代码

happypack

  1. TODO: 后续补充更新,欢迎留言发问,催更

    eslint

    CI/CD

    pre commit 检查

猜你喜欢

转载自juejin.im/post/7078664566531588110