为什么使用打包工具?
开发时,我们会使用框架(React、Vue),ES6 模块化语法,Less/Sass 等 css 预处理器等语法进行开发。
这样的代码要想在浏览器运行必须经过编译成浏览器能识别的 JS、Css 等语法,才能运行。
所以我们需要打包工具帮我们做完这些事。
除此之外,打包工具还能压缩代码、做兼容性处理、提升代码性能等。
一、基本配置
Webpack
是一个静态资源打包工具。
它会以一个或多个文件作为打包的入口,将我们整个项目所有文件编译组合成一个或多个文件输出出去。
输出的文件就是编译好的文件,就可以在浏览器运行了。
我们将 Webpack
输出的文件叫做 bundle
。
webpack的两个模式:
- 开发模式:仅能编译 JS 中的
ES Module
语法 - 生产模式:能编译 JS 中的
ES Module
语法,还能压缩 JS 代码
1.资源目录
webpack_code # 项目根目录(所有指令必须在这个目录运行)
└── src # 项目源码目录
├── js # js文件目录
│ ├── modules //自动加载文件夹
│ ├── test.js
│ └── main.js
└── index.js # 项目主文件
2. 创建文件 src/js/test.js
(($) => {
console.log('Test')
})(jQuery);
src/js/main.js
__webpack_public_path__ =
'项目目录/build/';
/*
* 自动加载,将js文件放在modules文件夹下 页面会全局加载modules下所有js文件
*/
const handleExecer = (modules) => {
Object.keys(modules).forEach((item) => {
const f = modules[item];
if (typeof f === 'function') f();
});
};
/**
* './modules' import directory
* true subdirectories
* /\.js$/ match the suffix for 'js' file
*/
const files = require.context('./modules', true, /\.js$/);
const modules = files.keys().reduce((module, path) => {
const name = path.replace(/^\.\/|.js$/g, '');
module[name] = files(path).default;
return module;
}, {});
handleExecer(modules);
/*
* 按需加载
*/
jQuery(() => {
const $ = jQuery;
const $body = $('body');
if ($body.hasClass('test')) { //如果body中含有‘test’这个class 则加载下面的js
import(/* webpackChunkName: 'test' */ './test');
}
});
src/index.js
require('./js/main');
3.下载依赖
打开终端,来到项目根目录。运行以下指令:
- 初始化
package.json
npm init -y
此时会生成一个基础的 package.json
文件。
需要注意的是 package.json
中 name
字段不能叫做 webpack
, 否则下一步会报
-
下载依赖
npm install
4. 启用 Webpack
- 开发模式
npx webpack ./src/index.js --mode=development
- 生产模式
npx webpack ./src/index.js --mode=production
npx webpack
: 是用来运行本地安装 Webpack
包的。
./src/index.js
: 指定 Webpack
从 main.js
文件开始打包,不但会打包 index.js
,还会将其依赖也一起打包进来。
--mode=xxx
:指定模式(环境)。
5. 观察输出文件
默认 Webpack
会将文件打包输出到 dist
目录下,我们查看 dist
目录下文件情况就好了
二、Webpack配置文件
5 大核心概念
- entry(入口)指示 Webpack 从哪个文件开始打包
- output(输出)指示 Webpack 打包完的文件输出到哪里去,如何命名等
- loader(加载器)webpack 本身只能处理 js、json 等资源,其他资源需要借助 loader,Webpack 才能解析
- plugins(插件)扩展 Webpack 的功能
- mode(模式)主要由两种模式:
- 开发模式:development
- 生产模式:production
准备 Webpack 配置文件
在项目根目录下新建文件:webpack.config.js
module.exports = {
// 入口
entry: "",
// 输出
output: {},
// 加载器
module: {
rules: [],
},
// 插件
plugins: [],
// 模式
mode: "",
};
Webpack 是基于 Node.js 运行的,所以采用 Common.js 模块化规范
修改配置文件
配置webpack.config.js
文件
const path = require('path');
// 配置打包单独css 文件,通过 link 标签加载
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin'); // 配置Stylint
const ESLintPlugin = require('eslint-webpack-plugin'); // 配置Eslint
module.exports = {
entry: {
main: './src/index.js', // 输入文件目录
},
output: {
filename: '[name].js',
chunkFilename: '[name].bundle.js?h=[contenthash]',
path: path.resolve(__dirname, 'build'), //修改打包输出目录
clean: true, // 自动清空上次打包目录
},
module: {
rules: [
{
test: /\.scss$/, // 用来匹配.scss结尾的文件
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
url: false,
},
},
'postcss-loader',
'sass-loader',
],
},
{
test: /\.(png|svg|jpg|gif)$/, // 用来匹配.png|svg|jpg|gif结尾的文件
type: 'asset',
},
{
test: /\.js$/, // 用来匹配.js结尾的文件
exclude: /(node_modules|bower_components)/,
use: [
{
loader: 'babel-loader',
},
],
},
],
},
plugins: [
new MiniCssExtractPlugin(), // 加载打包单独css文件插件
new StyleLintPlugin({ // 加载styleLint插件
context: 'src',
configFile: path.resolve(__dirname, './.stylelintrc.json'),
files: ['**/*.scss'],
fix: false,
cache: true,
emitErrors: true,
failOnError: false,
}),
new ESLintPlugin(), // 配置Eslint
],
optimization: {
splitChunks: {
chunks: 'all',
},
},
};
1.处理 Css 资源
下载包
npm i css-loader style-loader -D //需要下载两个loader
功能介绍
css-loader
:负责将 Css 文件编译成 Webpack 能识别的模块style-loader
:会动态创建一个 Style 标签,里面放置 Webpack 中 Css 模块内容
此时样式就会以 Style 标签的形式在页面上生效
2.处理 Sass 和 Scss 资源
下载包
npm i sass-loader sass -D
功能介绍
sass-loader
:负责将 Sass 文件编译成 css 文件sass
:sass-loader
依赖sass
进行编译
配置styleLint
- .stylelintrc.json文件
{
"extends": "stylelint-config-standard-scss",
"plugins": [
"stylelint-order"
],
"rules": {
"property-no-vendor-prefix": null,
"selector-pseudo-class-no-unknown": null,
"scss/at-extend-no-missing-placeholder": null,
"selector-class-pattern": null,
"comment-empty-line-before": null,
"function-linear-gradient-no-nonstandard-direction": null,
"function-whitespace-after": null,
"no-descending-specificity": null,
"no-duplicate-selectors": null,
"no-unknown-animations": true,
"media-feature-name-no-unknown": [true, {
"ignoreMediaFeatureNames": [
"prefers-reduced-motion",
"min--moz-device-pixel-ratio"
]
}],
"value-no-vendor-prefix": [true, {
"ignoreValues": [
"box"
]
}],
"number-leading-zero": "always",
"order/order": null,
"property-no-unknown": null,
"rule-empty-line-before": null,
"selector-pseudo-element-colon-notation": null,
"shorthand-property-no-redundant-values": null,
"string-quotes": "double",
"value-keyword-case": ["lower", {
"ignoreProperties": [
"--font-family",
"font-family"
]
}],
"at-rule-no-unknown": [true, {
"ignoreAtRules": ["if", "else", "warn", "each", "include", "mixin", "extend"]
}],
"font-family-no-missing-generic-family-keyword": null
},
"ignoreFiles": [
"dist/*.css"
]
}
相关Sass 配置见上面配置webpack.config.js
文件
3.处理图片资源
过去在 Webpack4 时,我们处理图片资源通过 file-loader
和 url-loader
进行处理
现在 Webpack5 已经将两个 Loader 功能内置到 Webpack 里了,我们只需要简单配置即可处理图片资源
相关图片配置 配置见上面配置webpack.config.js
文件
4.处理js资源
Webpack 对 js 处理是有限的,只能编译 js 中 ES 模块化语法,不能编译其他语法,导致 js 不能在 IE 等浏览器运行,所以我们希望做一些兼容性处理。
其次开发中,团队对代码格式是有严格要求的,我们不能由肉眼去检测代码格式,需要使用专业的工具来检测。
- 针对 js 兼容性处理,我们使用 Babel 来完成
- 针对代码格式,我们使用 Eslint 来完成
我们先完成 Eslint,检测代码格式无误后,在由 Babel 做代码兼容性处理
Eslint
.eslintrc.json文件
{
"parser": "@babel/eslint-parser",
"extends": [
"airbnb",
"plugin:prettier/recommended"
],
"root": true,
"env": {
"browser": true,
"es6": true,
"node": true
},
"globals": {
"Drupal": true,
"drupalSettings": true,
"drupalTranslations": true,
"jQuery": true,
"_": true,
"Cookies": true,
"Backbone": true,
"Modernizr": true,
"Popper": true,
"Shepherd": true,
"Sortable": true,
"once": true,
"CKEDITOR": true,
"tabbable": true,
"AOS": true
},
"settings": {
"react": {
"version": "latest"
}
},
"rules": {
"new-cap": ["off"],
"prettier/prettier": "error",
"consistent-return": ["off"],
"no-underscore-dangle": ["off"],
"max-nested-callbacks": ["warn", 5],
"import/no-mutable-exports": ["warn"],
"no-plusplus": ["warn", {
"allowForLoopAfterthoughts": true
}],
"no-param-reassign": ["off"],
"no-prototype-builtins": ["off"],
"valid-jsdoc": ["warn", {
"prefer": {
"returns": "return",
"property": "prop"
},
"requireReturn": false
}],
"no-unused-vars": ["warn"],
"operator-linebreak": ["error", "after", { "overrides": { "?": "ignore", ":": "ignore" } }],
"import/no-extraneous-dependencies": [ "error", { "devDependencies": [ "**/webpack.*.js" ] }],
"import/prefer-default-export": "off",
"func-names": "off",
"no-restricted-syntax": "off",
"global-require": 0
}
}
在 Webpack 中使用
下载包
npm i eslint-webpack-plugin eslint -D
相关Eslint 配置见上面配置webpack.config.js
文件
Babel
JavaScript 编译器。
主要用于将 ES6 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中
.baberlc.json
{
"presets": ["@babel/preset-env"],
"compact": false
}
在 Webpack 中使用
下载包
npm i babel-loader @babel/core @babel/preset-env -D
相关Babel 配置见上面配置webpack.config.js
文件
三、生产/开发模式准备
我们分别准备两个配置文件来放不同的配置
1. 文件目录
├── webpack-test (项目根目录)
├── config (Webpack配置文件目录)
│ ├── webpack.dev.js(开发模式配置文件)
│ └── webpack.prod.js(生产模式配置文件)
├── node_modules (下载包存放目录)
├── src (项目源码目录,除了html其他都在src里面)
│ └── 略
├── .eslintrc.json(Eslint配置文件)
├── babelrc.js(Babel配置文件)
webpack.dev.js
const { merge } = require('webpack-merge');
const common = require('./webpack.config');
module.exports = merge(common, {
mode: 'development',
devtool: 'source-map',
});
webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.config');
module.exports = merge(common, {
mode: 'production',
});
最后,运行以下命令执行对应操作
run `npm start` // 开发运行
run `npm run build` // 生产打包文件