前端工程化之webpack5基本配置

643 阅读9分钟

1.创建新项目目录,并进入文件夹,初始化package.json文件

mkdir webpack5-pro
cd webpack5-pro
npm init -y

2.安装webpackwebpack-cli

npm i webpack webpack-cli -D

查看package.json文件,可以看到webpackwebpack-cli的包已经安装成功。

{
  "name": "Code",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    // 开发环境依赖
    "webpack": "^5.67.0",
    "webpack-cli": "^4.9.2"
  }
}

3.创建项目的源码目录src

工程化项目的源代码目录src创建完成之后,新建项目的入口文件index.js,写入一下测试代码:

function helloWebpack (name){
    console.log("webpack,你好啊!我是" + name )
}
helloWebpack("hunhunzhang")

4.在项目根目录下新建webpack打包后的文件输出的目录distwebpack.config.js配置文件

// webpack.config.js文件的基本配置如下
const path = require("path")

module.exports = {
    // 打包模式
    // mode: 'development',
    // 入口文件
    entry: path.resolve(__dirname,'./src/index.js'),
    // 出口目录
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname,'./dist')
    }
}

5.修改package.json文件的scripts脚本配置,启用webpack

{
  "name": "Code",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    // webpack打包脚本配置
    "build": "webpack"
  }
}

6.初次打包,测试打包情况,运行命令后,当你看到dist的目录下有bundle.js文件,说明成功

// 运行测试打包的脚本命令
npm run build

// 打包后的bundle.js文件内容
/*
 * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
 * This devtool is neither made for production nor for readable output files.
 * It uses "eval()" calls to create a separate source file in the browser devtools.
 * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
 * or disable the default devtool with "devtool: false".
 * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
 */
/******/ (() => { // webpackBootstrap
/******/ 	var __webpack_modules__ = ({

/***/ "./src/index.js":
/*!**********************!*\
  !*** ./src/index.js ***!
  \**********************/
/***/ (() => {

eval("function helloweb(name){\r\n\tconsole.log('hwlo' + name)\r\n}\r\nhelloweb('hhz')\n\n//# sourceURL=webpack://Code/./src/index.js?");

/***/ })

/******/ 	});
/************************************************************************/
/******/ 	
/******/ 	// startup
/******/ 	// Load entry module and return exports
/******/ 	// This entry module can't be inlined because the eval devtool is used.
/******/ 	var __webpack_exports__ = {};
/******/ 	__webpack_modules__["./src/index.js"]();
/******/ 	
/******/ })()
;

7.区分打包的的环境时生产(prod)还是开发(dev),分类处理

当项目较大时候,需要根据不同的环境进行不同的配置来完成想要的操作,所以,需要拆分webpack配置文件:

1)创建一个config文件夹,用来存放不同配置的文件:

  • webpack.common.js用来配置webpack公共的配置
  • webpack.dev.js开发环境的配置
  • webpack.prod.js生产环境的配置

2)在不同的配置文件中,使用webpack-merge中的merge来合并公共的webpack文件(webpack4是根据smart来进行合并配置的)

npm i webpack-merge -D

3)不同配置文件的源码:

  • webpack.common.js
const path = require("path")
const srcPath = path.join(__dirname,"..","src")
module.exports = {
    entry: path.join(srcPath,"index.js")
}
  • webpack.dev.js
const path = require("path")
const conmonConfig = require("./webpack.common")
const { merge } = require("webpack-merge")
const devConfig = {
    mode: 'development',
    output: {
        filename: "bundle.js",
        path: path.join(__dirname,"..","dist")
    }
}
module.exports = merge(commonConfig,devConfig)
  • webpack.prod.js
const path = require('path')
const commonConfig = require('./webpack.common.js')
const {merge} = require('webpack-merge')

const prodConfig = {
  mode: 'production', // 生产环境
  output: {
    filename: 'bundle.[chunkhash].js',  // 输出文件名,一般要加上hash
    path: path.join(__dirname, '..', 'dist')  // 输出目录
  }
}
module.exports = merge(commonConfig, prodConfig)

8.package.json中配置不同webpack环境的命令:

为了让我们在开发阶段,不需要修改一次文件就手动的去进行webpack进行编译,所以安装webpack-dev-server插件来进行开发:

npm i webpack-dev-server -D

注意:在webpack4中开发环境使用的命令是webpack-dev-server --config config/webpack.dev.js,在webpack5中,改成了webpack server。脚本命令配置如下:

"scripts": {
    "build": "webpack --config config/webpack.prod.js",
    "dev": "webpack server --config config/webpack.dev.js"
},

运行脚本,查看结果:

npm run build
npm run dev

9.创建.html文件

可以进行打包js资源之后,那么就需要创建一个.html文件来加载打包编译后的.js文件,查看结果,在根目录下创建index.html,但是,生产环境我们往往会生成不同的hash值来防止资源缓存,所以每次生成的文件名都是不同的,手动引入入口文件往往不太现实,所以需要借助html-webpack-plugin插件来自动生成项目中的html页面,并实现自动导入对应脚本。

安装html-webpack-plugin,并在公共的webpack配置文件中去使用此插件

// 安装
npm i html-webpack-plugin -D

// 配置
const path = require("path")
const srcPath = path.join(__dirname, "..", "src")
// 引入html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
	entry: path.join(srcPath, "index.js"),
	plugins: [
		new HtmlWebpackPlugin({
			// 选择根目录下的index.html文件为模板文件,在dist文件夹下自动生成
			// 注意,这里是相对根目录而言的,因为脚本的上下文是在根目录下
			template: 'index.html'
			// inject: 'head', // 脚本注入的位置,可以是head, body,或者为 false默认
			// 在这里还可以自定义参数,在模板中,使用ejs方式 <%= htmlWebpackPlugin.options %>获取自定义属性
			title: 'Webpack Test',
			// webpack5默认开启压缩属性,webpack4要手动设置
			// minify: {
			//   removeComments: true, // 删除注释
			//   collapseWhitespace: true  // 删除空格
			// }
		})
	]
}

运行npm run build测试,dist目录下是否生成index.html文件,并且自动加载打包好的js文件.

10.clean-html-plugin删除之前的打包文件

我们在打包的过程中发现,每一次的打包,之前的文件包还是存在的,需要手动的去删除,不然影响打包文件的目录显得很乱,心里也是很难受。这个时候码农的偷懒精神就得以展现的淋漓尽致啦。使用clean-webpack-plugin插件,可以邦族我们在每一次打包文件之前,将之前的打包的旧文件包进行删除,生成最新的打包文件;

  • 安装插件:
npm i clean-webpack-plugin -D
  • webpack公共文件中进行配置
const path = require("path")
const srcPath = path.join(__dirname, "..", "src")
// 引入html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 引入clean-html-plugin
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
module.exports = {
	entry: path.join(srcPath, "index.js"),
	plugins: [
		new HtmlWebpackPlugin({
			// 选择根目录下的index.html文件为模板文件,在dist文件夹下自动生成
			// 注意,这里是相对根目录而言的,因为脚本的上下文是在根目录下
			template: 'index.html',
			// inject: 'head', // 脚本注入的位置,可以是head, body,或者为 false默认
			// 在这里还可以自定义参数,在模板中,使用ejs方式 <%= htmlWebpackPlugin.options %>获取自定义属性
			title: 'Webpack Test'
			// webpack5默认开启压缩属性,webpack4要手动设置
			// minify: {
			//   removeComments: true, // 删除注释
			//   collapseWhitespace: true  // 删除空格
			// }
		}),
		// 打包前删除上次的打包文件
		new CleanWebpackPlugin()
	]
}

到目前为止,只要是按照这个步骤一步一步进行配置的,前端的环境是完全没有问题的!

11.NODE_ENV=?配置环境的全局变量

我们通常会有个配置文件,需要根据环境的不同,配置不同的接口地址,这时一般就会用到全局变量,webpack可以使用DefinePlugin插件来设置全局变量,我们一般在package.json文件运行脚本中,会自定义一个环境变量NODE_ENV,这个变量就可以在webpack的公共文件进行访问了process.env.NODE_ENV,但是在其他的js文件中是获取不到的,但是可以在webpack.common.js中进行配置(设置为全局变量),以后再其他的js文件中也是可以访问这个变量的:

// webpack.common.js
 plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
    })
  ]

现在基本上不存在这个问题了,因为对于5来说,mode的配置值,就是这个变量,所以利用webpack5的童鞋们就不要再配置上面的plugins了:

// mac电脑
"scripts": {
    "build": "NODE_ENV=prod webpack --config config/webpack.prod.js",
    "dev": "NODE_ENV=dev webpack server --config config/webpack.dev.js NODE_ENV=development"
},
// windows电脑
"scripts": {
    "build": "set NODE_ENV=prod && webpack --config config/webpack.prod.js",
    "dev": "set NODE_ENV=dev && webpack server --config config/webpack.dev.js NODE_ENV=development"
},

12.npm run dev开发环境的配置

在前面的时候,这个脚本是我们配置过的,dev就是development表示的是开发环境,因为我们配置了入口html文件了,所以可以运行命令npm run dev进行启动开发的服务器,再次改变只要保存就行了,不需要一直进行编译。

1)跨域问题进行配置

webpack.dev.js设置devServer:

const path = require("path")
const commonConfig = require("./webpack.common.js")
const {
	merge
} = require('webpack-merge')
const devConfig = {
	mode: 'development',
	output: {
		filename: 'bunlder.js',
		path: path.join(__dirname, "..", "dist")
	},
	devServer: {
		// 设置代理
		proxy: {
			// 将本地默认域名localhost:8080 代理到 localhost:6666/xxx,/api2/xxx  ,通常用这个,/api2仅作为代理转发的标识
			'/api2': {
				target: 'http://localhost:3000',
				changeOrigin: true,
				pathRewrite: {
					// 如果带有 ^ 最终访问的路径是去除/api2的,去除代理的命名
					'^/api2': ''
				},
				secure: false
			}
		}
	}
}
module.exports = merge(commonConfig, devConfig)

13.样式文件.css/.less等样式文件处理

如果我们在index.js文件通过import './style/css/index.css'样式文件时,进行webpack打包的时候会出现错误,因为啊,webpack只能认识.js文件,其他类型的文件,它是不认识的,就需要我们借助loader来处理样式类的文件,转换成js可以处理的文件。

注意:我时安装了两个loader,但是还会进行报错,后来找到解决方案,在index.js入口文件中引入css文件时候格式须这样写: import "style-loader!css-loader!./css/index.css",就是在路径前面加上loader名称和! 图片.png

1)处理.css文件

  • 安装相关loader
npm i css-loader style-loader -D
  • webpack.common.js文件中配置module.rulesloader处理规则
const path = require("path")
const srcPath = path.join(__dirname, "..", "src")
// 引入html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 引入clean-html-plugin
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
module.exports = {
	entry: path.join(srcPath, "index.js"),
	plugins: [
		new HtmlWebpackPlugin({
			// 选择根目录下的index.html文件为模板文件,在dist文件夹下自动生成
			// 注意,这里是相对根目录而言的,因为脚本的上下文是在根目录下
			template: 'index.html',
			// inject: 'head', // 脚本注入的位置,可以是head, body,或者为 false默认
			// 在这里还可以自定义参数,在模板中,使用ejs方式 <%= htmlWebpackPlugin.options %>获取自定义属性
			title: 'Webpack Test'
			// webpack5默认开启压缩属性,webpack4要手动设置
			// minify: {
			//   removeComments: true, // 删除注释
			//   collapseWhitespace: true  // 删除空格
			// }
		}),
		// 打包前删除上次的打包文件
		new CleanWebpackPlugin()
	],
	// loader配置
	module: {
		rules: [
			{
				test: '/\.css$/', //匹配规则
				use: ['style-loader','css-loader'] //使用的loader
			}
		]
	}
}

2)处理.less.scss文件和上面一样

  • 安装相关loader
npm i css-loader style-loader less-loader less -D
  • webpack.common.js文件中配置module.rulesloader处理规则
module: {
		rules: [
			{
				test: '/\.css$/', //匹配规则
				use: ['style-loader','css-loader'] //使用的loader
			},
			{
				test: '/\.less$/', //匹配规则
				use: ['style-loader','css-loader','less-loader'] //使用的loader
			}
		]
	}

3)为了提高css的兼容性,适配不同的浏览器厂商,可以利用插件为css自动添加前缀

  • 安装相关loader
`npm i postcss-loader autoprefixer -D`
  • webpack.common.js文件中配置module.rulesloader处理规则
module: {
    rules: [
      {
        test: /.css$/,
        use: ['style-loader', 'css-loader', 'postcss-loader']
      },
      {
        test: /.less$/,
        use: ['style-loader', 'css-loader','postcss-loader',  'less-loader']
      }
    ]
},
plugins: [
    require('autoprefixer')
]

4)生产环境中将css文件进行抽离,与html文件不进行混合

  • 安装相关loader
`npm i mini-css-extract-plugin -D`
  • webpack.prod.js文件中配置,将前面的 style-loader换成mini-css-extract-pluginloader
const path = require('path')
const commonConfig = require('./webpack.common.js')
const {
	merge
} = require('webpack-merge')
// 引入在生产环境中,将css文件进行抽离的插件: mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

const prodConfig = {
	mode: 'production', // 生产环境
	output: {
		filename: 'bundle.[chunkhash].js', // 输出文件名,一般要加上hash
		path: path.join(__dirname, '..', 'dist') // 输出目录
	},
	module: {
		rules: [{
				test: '/\.css$/',
				use: [MiniCssExtractPlugin.loader, 'css-loader']
			},
			// {
			// 	test: '/\.less$/',
			// 	use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader']
			// }
		]
	},
	plugins: [
		new MiniCssExtractPlugin({
			filename: 'css/[name]_[contenthash].css',
			chunkFilename: '[name]_[contenthash].css'
			
		})
	]
}
module.exports = merge(commonConfig, prodConfig)

在我使用这个分离插件打包的时候,没有报错,但是css文件在打包后也是没有进行分离出来,这里算是没有成功的,后面如果成功了,就回来更新方法。

5) 图片等资源文件的处理

如果要在js中像引用其他的.css一样,引用图片资源并容易使用(import img from './images/a.jpg'),或者在.css中设置背景图(background: url('../images/b.png'),这个时候就需要处理图片资源的loader来解决这个问题了。

目前市场上用户较多的两款loader是:file-loaderurl-loader,两款loader差不多,只是url-loader多出来一个可以设置根据文件大小来决定是否进行base6的转换的功能。

  • file-loader(开发环境) 1.安装: npm i file-loader -D 2.webpack.dev.js配置:
// 处理css样式文件中的url图片
{
   test: /.(jpg|png|jpeg|gif)$/,
   use: ['file-loader']
}
  • url-loader(生产环境) 1.安装: npm i url-loader -D 2.在webpack.dev.js和webpack.common.js配置此loader:
module: {
       rules: [
                {
		// 正则匹配的时候,正则表达式不需要进行加上引号
			test: /\.(jpg|png|jpeg|gif)$/,
			use: {
				loader: 'url-loader',
				options: {
					limit: 8192, //配置项,是限制图片如果是小于8kb的就将图片转换为base64
					esModule: false,
					name: '[name]_[hash:8].[ext]',
					outputPath: 'images' //打包到/images目录下面
				}
			}
		}
	]
},

6)处理ES6+的代码

虽然webpack本身就是可以处理js代码的,但是一些比较新的代码,比如ES6之上的新特性,webpack也是处理不了的,这个时候也需要特定的处理的loader来进行处理,babel-loader就是最常用的处理新特性的loader:

  • 安装loader npm i babel-loader @babel/core @babel/preset-env -D
  • 配置
// babel-loader处理js
{
	test: /\.js$/,
	use: ['babel-loader'], //缓存
	include: srcPath, // 缩小查询范围
	exclude: /node_modules/ //排除要处理的文件夹
}
// 在项目的根目录创建,.babelrc
{
  "presets": ["@babel/preset-env"],  // 一般使用@babel/preset-env就够了
  "plugins": []
}
// 对于babel版本高于v7.8.0,可以将.babelrc 变为在根目录创建 babel.config.json
{
  "presets": [
    [
      "@babel/env",
      {
        "targets": {
          "edge": "17",
          "firefox": "60",
          "chrome": "67",
          "safari": "11.1"
        },
        "useBuiltIns": "usage",
        "corejs": "3.6.5"
      }
    ]
  ]
}

7)引用文件路径使用@操作符

为了更好的引用资源路径,配置路径引用还是蛮好的,配置如下:

resolve: {
    alias: {
     '@': path.resolve(__dirname,'./src')
    }
}

以上就是最常用的项目工程化的webpack的配置啦,如果后续有更好的配置,我会进行更新加载进来。