以下内容来自 拉勾教育大前端训练营 以及在学习过程中对笔记上进行的一个整理,
该文将使用Webpack 版本4.43.0, node.js 版本 10.21,将从以下二个部分来使用webpack进行深入使用
Webpack
到深入Webpack
是一种前端构建工具, 一个静态模块打包器(module bunder).
在Webpack
看来, 前端所有的资源文件(js/json/css/img/less/…)都会作为模块处理
它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。
Plugin
扩展,完整好用又不失灵活入口 Entry
入口 Entry
指示Webpack
以那个文件为入口起点开始打包,分析构建内部依赖图
module.exports = {
entry: './src/index.js'
};
输出 (Output)
output
属性告诉 Webpack
在哪里输出它所创建的bundles
,以及如何命名这些文件,默认值为./dist
基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。你可以通过在配置中指定一个 output
字段,来配置这些处理过程
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
};
Loader
loader
让Webpack
能够去处理那些非JavaScript文件(webpack 自身只理解 JavaScript)loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
]
}
Plugin
Plugin
用于扩展 Webpack
的功能,各种各样的Plugin
几乎可以让 Webpack
做任何与构建相关的事情, Plugin
的配置很简单,Plugins
配置项接收一个数组,数组里面的每一项都是一个要使用Plugin的实例。
// yarn add html-webpack-plugin --dev
const HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
})
]
模式 (mode)
告诉Webpack使用相应模式的内置优化
development
能让代码把本地调试运行环境
production
能让代码运行优化上线运行的环境
module.exports = {
mode: 'production',
<!--mode: 'development'-->
};
yarn webpack webpack-cli --dev
到开发环境mkdir webpack-demo
cd webpack-demo
// 目录
// 初始化package.json
yarn init --yes
// 安装webpack, webpack-cli 到devDependencies 开发环境依赖中
yarn webpack webpack-cli --dev
// heading.js
export default () => {
let element = document.createElement('h1');
element.textContent = 'Hello Webpack';
element.className = 'title';
return element
}
// index.js
import createHeading from './heading.js'
const heading = createHeading()
document.body.append(heading)
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello Webpack</title>
</head>
<body>
<script src="./src/index.js"></script>
</body>
</html>
yarn webpack
命令, 接着我们的根目录下就有一个为dist文件,里面有个main.js,然后我们将index.html中的属性修改为dist文件,打开就可以直接看到我们创建的一个h1标签了yarn build
就行了<script src="./dist/main.js"></script>
"scripts": {
"build": "webpack"
},
处理样式文件我们需要借助loader
, 一般常用的loader
有 css-loader
less-loader
sass-loader
在根目录下创建 webpack.config.js
在src
目录下创建css文件夹, index.css, index.less
样式可以随便写
安装依赖
yarn add style-loader css-loader less-loader --dev
// webpack.config.js
// resolve 用来拼接绝对路径的方法
const { resolve } = require('path')
module.exports = {
// webpack配置
// 入口起点
entry: './src/index.js',
// 输出
output: {
filename: 'bundle.js', // 输出文件名
// __dirname是node.js的变量,代表当前文件目录绝对路径
path: resolve(__dirname, 'dist') // 输出路径
},
// 详细loader配置
module: {
rules: [
{
test: /\.(css|less)$/, // 匹配css 文件
use: [
'style-loader',
'css-loader',
'less-loader'
]
}
]
},
// plugins的配置
plugins: [],
// 模式
mode: 'development', // 开发模式
// mode: 'production',
}
这几个loader的作用
style-loader
动态创建style
标签,将 js
中的样式资源插入进行css-loader
将css 文件变成commonjs
模块加载到js中less-loader
将less文件编译成css
文件注意:
loader
执行顺序,它是从下到上, 或者说从右到左pre
,可以修优先级接着我们可以去执行打包
执行yarn build
命令, 再次运行index.html
可以看到样式资源也被打包到了bundle.js
, 不过这里我们还是要去手动修改一下index.html
的 js
文件。后面我们会将html一起打包就不需要手动引入了
html-webpack-plugin
的作用是什么呢,其实它的作用就是帮助我们将打包的js
文件以及css
等静态资源文件文件自动引入到index.html
中,原来我们都需要手动引入,太累了,emmm 我们需要懒一点
首先安装依赖
yarn add html-webpack-plugin --dev
// webpack.config.js 头部引入
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 在plugin中使用
module.exports = {
plugins: [
// 默认创建一个空HTML,自动打包输出的所有资源,这里对应index.html文件
new HtmlWebpackPlugin({
// 复制 './index.html'文件,并自动打包引入输出所有资源
template: './index.html'
})
]
}
执行 yarn build
打包完成后dist目录此时会多出一个index.html
文件,此时可以看到index.html
中会把我们的js资源文件自动插入到页面中
我们在项目开发中,肯定少不了引入本地图片资源,那如何处理图片资源呢,我们还需要用loader
去处理它
可以用 url-loader
或者 file-loader
来处理本地的资源文件
yarn add url-loader html-loader --dev
{
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
// 图片大小小于10kb,就会被base64处理
// 优点: 减少请求数量(减轻服务器压力)
// 缺点: 图片体积会更大(文件请求速度更慢)
limit: 10 * 1024,
esModule: false,
name: '[hash:10].[ext]',
outputPath: 'image'
}
},
{
test: /\.html$/,
// 处理html文件img图片
loader: 'html-loader',
},
// 因为url-loader默认是使用es6模块化解析的,而html-loader引入图片是commonjs,
// 解析会出现问题:[object Module],使用commonjs解析
// 关闭url-loader的es6 module esModule: false
url-loader的配置
limit: 10*1024
即图片大小小于10kb
的时候,就会被base64
处理,超过10kb
的就会被拷贝到dist目录,这里这么做优点是可以减少请求数量(减轻服务器的压力),缺点图片的体积会更大(文件请求速度更慢)
esmMoule: false
这里是为了解决 会出现
的问题
name: '[hash:10].[ext]
给图片重命名, [hash:10] 取图片前10位
outputPath:
输出目录
执行 yarn build
对于字体图片文件我们可以使用url-loader
或者file-loader
这里我是在阿里矢量图标库下了几个字体图标文件
yarn add file-loader --dev
阿里矢量图标库
// src 目录创建font
// index.js 导入iconfont.css
import './font/iconfont.css'
// index.html添加图标
<span class="iconfont icon-caihong"></span>
<span class="iconfont icon-qiwen-diwen"></span>
<span class="iconfont icon-ganzao"></span>
<span class="iconfont icon-rishi-riquanshi"></span
用来处理ES6
语法,将其编译为浏览器可以执行的js
语法
由于Webkpack
默认就能处理我们的代码中的export
和import
,但是并不能转换其他的ES6
等新特性,我们需要为js文件配置一个额外的编一些型loader
,那最常见最常见的就是babel-loader
,由于babael-loader
需要额外的依赖于babel核心模块,所以我们需要安装多个模块,以及用于去完成具体 的特性转换插件的集合叫babel/preset-env
安装依赖
yarn add babel-loader @babel/core @babel/preset-env --dev
{
test: /\.js$/,
exclude: /node_modules/, // 排除 node_modules 目录
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
执行yarn build
此时我们再去看dist
目录,会发现js
文件中的箭头函数等属性被转换es5
在之前打包每次都会留下原来的文件,需要手动删除,那么如何能自动删除呢,我们需要加入了这个插件后在打包前每次都会自动清除了。是不是很方便呢
安装依赖
yarn add clean-webpack-plugin --dev
// webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
// 使用
plugins: [
new CleanWebpackPlugin()
],
Source Map
是一种提供源代码到构建后代码映射技术,如果构建后代码出错了,构建后的代码和源代码千差万别,找代码出错位置难,可读性非常差,sourc-map
之后, 构建后的代码出错了可以追踪源代码的错误,利于我们调试,找出代码出错的原因。Webpack
支持转换生成的代码输出对应Source Map
文件,以方便在浏览器中调试,控制Source Map输出的Webpack
配置选项是devtool
,他有很多选项具体可以看这里 Source Map
开发环境推荐
cheap-module-eval-source-map
能够定位到错误代码的准确信息和源代码错误位置, 综合构建速度
生产环境推荐
源代码要不要隐藏
使用 none
或者source Map
, 不暴露源代码
// resolve 用来拼接绝对路径的方法
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
// webpack配置
// 入口起点
entry: './src/index.js',
// 输出
output: {
filename: 'bundle.js', // 输出文件名
// __dirname是node.js的变量,代表当前文件目录绝对路径
path: resolve(__dirname, 'dist') // 输出路径
},
devServer: {
contentBase: resolve(__dirname, 'dist'),
compress: true, // 启动gzip压缩
port: '3000', // 端口号,
open: true, // 自动打开浏览器
},
// 详细loader配置
module: {
rules: [
{
test: /\.(css|less)$/,
use: [
// use数组中loader执行顺序,从下到上
// 创建style标签,将js中的样式资源插入进行
'style-loader',
// 将css 文件变成commonjs模块加载到js中
'css-loader',
// 将less文件编译成css文件
'less-loader'
]
},
{
// 处理图片
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
// 图片大小小于10kb,就会被base64处理
// 优点: 减少请求数量(减轻服务器压力)
// 缺点: 图片体积会更大(文件请求速度更慢)
limit: 10 * 1024,
esModule: false,
// [hash:10] 取图片前10位
name: '[hash:10].[ext]',
outputPath: 'image'
}
},
{
test: /\.html$/,
// 处理html文件img图片
loader: 'html-loader'
},
{
test: /\.(eot|woff2?|ttf|svg)$/,
use: [
{
loader: "file-loader",
options: {
name: "[name]-[hash:5].min.[ext]",
limit: 3000,
outputPath: 'font',
}
}
]
}
]
},
// plugins的配置
plugins: [
// 默认创建一个空HTML,自动打包输出的所有资源,这里对应index.html文件
new HtmlWebpackPlugin({
// 复制 './index.html'文件,并自动打包引入输出所有资源
template: './index.html'
}),
new CleanWebpackPlugin()
],
// 模式
mode: 'development', // 开发模式
// mode: 'production', // 生产模式
}
yarn add webpack-dev-server --dev
devServer: {
contentBase: resolve(__dirname, 'dist'),
compress: true, // 启动gzip压缩
port: '3000', // 端口号,
open: true, // 自动打开浏览器
},
"scripts": {
"serve": "webpack-dev-server --open --config webpack.config.js",
}
devServer: {
contentBase: resolve(__dirname, 'dist'),
watchContentBase: true, // 监视contentBase目录下的所有文件,一旦文件变化就会reload
wacthOptions: {
ignored: /node_modules/
},
compress: true, // 启动gzip压缩
port: 8020, // 端口
host: 'loaclhost', 域名
hot: HMR, // 开启HMR功能
clientLogLevel: 'none', // 不要显示启动服务器日志信息
quiet: true, // 除了一些基本期待能够信息以外,其他内容都不要显示
overlay: false, // 如果出错了,不要全屏提示
proxy: {}, // 服务器代码 ---> 解决开发环境跨域问题
}
webpack-dev-server只会在内存中编译打包,不会有任何输出
执行 yarn serve 此时就会自动打开浏览器啦,并且会自动编译,自动刷新浏览器,提升开发体验。
yarn add mini-css-extract-plugin --dev
// 这里我们为了构建生产环境 新建一个文件webpack.prod.js
// 同时在package.json 可以加入
"scripts": {
"serve": "webpack-dev-server --open --config webpack.config.js",
"build:prod": "webpack --open --config webpack.prod.js",
"build": "webpack"
},
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// 我们需要将style-loader 替换成 MiniCssExtractPlugin.loader
rules: [
{
test: /\.(css)$/,
// 使用哪些loader
use: [
// use 数组中loader 执行顺序, 从右到左,从下到上一次执行
// MiniCssExtractPlugin取代style.loader
// 提取js中的单css 成单独文件
{
loader: MiniCssExtractPlugin.loader
},
'css-loader', // 将css文件变成commonjs 模块加载到模块中,里面内容是字符串
]
},
{
test: /\.(less)$/,
// 使用哪些loader
use: [
// use 数组中loader 执行顺序, 从右到左,从下到上一次执行
// MiniCssExtractPlugin取代style.loader
// 提取js中的单css 成单独文件
{
loader: MiniCssExtractPlugin.loader
},
'css-loader', // 将css文件变成commonjs 模块加载到模块中,里面内容是字符串
'less-loader' // 将less文件编译成css 文件
]
}
]
plugins: [
new MiniCssExtractPlugin({
filename: 'css/common.css'
})
]
这里我们需要用到postcss-loader
, PostCSS
( http://postcss.org)是一个 css
处理工具,和 scss
的不同之处在于它可以通 过插件机制灵活地扩展其支持的特性,而不像 scss
那样语法是固定的。 PostCSS
的用处非 常多,包括向 css
自动加前缀、使用下一代 css
语法等。
安装依赖
yarn add postcss-loader postcss-preset-env --dev
修改css-loader
配置
{
test: /\.css$/,
use: [
// use数组中loader执行顺序,从下到上
// 创建style标签,将js中的样式资源插入进行
// MiniCssExtractPlugin取代style.loader
{
loader: MiniCssExtractPlugin.loader
},
// 将css 文件变成commonjs模块加载到js中
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
require('postcss-preset-env')()
]
}
}
]
}
在 package.json
中的browserslist
里面的配置,通过配置兼容指定的css 兼容性样式
"borwserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"prodection": [
">0.2%",
"not dead",
"not op_min all"
]
},
测试一下,加入transition
打包之后 默认会给我们添加前缀–webkit
.container img {
width: 300px;
height: 300px;
transition: width 2s, height 2s, background-color 2s, transform 2s;
border-radius: 20px;
}
.container img:hover{
transform: rotate(180deg);
}
在生产环境中,我们需要对代码进行优化,为的就是我们的应用能在线上性能的快,很好的运行,所以这里我们需要使用 optimize-css-assets-webpack-plugin
这个插件来帮助我们对代码进行压缩
yarn add optimize-css-assets-webpack-plugin --dev
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
// 使用很简单,只需调用new
plugins: [
// 压缩css
new OptimizeCssAssetsWebpackPlugin()
]
对HTML文件压缩其实也是为了优化应用的加载速度,在plugins中配置HtmlwebpackPlugin
加入minify
参数就行了
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
// 移除空格
collapseWhitespace: true,
removeComments: true // 移除注释
}
}),
随意我们需要使用ESLint来帮助我们约束代码规范
parser
(指定解析器)
babel-eslint
解析器是一种使用频率很高的解析器,因为现在很多公司的很多项目目前都使用了es6
,
为了兼容性考虑基本都使用babel插件对代码进行编译。而用babel
编译后的代码使用 babel-eslint
这款解析器可以避免不必要的麻烦
安装依赖
yarn add eslint eslint-loader babel-eslint --dev
// 新建.eslintrc.js
module.exports = {
"extends": "airbnb-base",
root: true,
parserOptions: {
sourceType: 'module',
},
parser: 'babel-eslint',
env: {
browser: true,
es6: true
},
rules: {
"indent": ["error", 2], // 代码缩进
"semi": [1, "always"], // 要求在语句末尾使用分号
"camelcase": [2, {"properties": "always"}], // 强制属性名称为驼峰风格
"object-curly-spacing": "never", // 不允许花括号中有空格
"no-var": '',
"no-alert": 0 // 禁止使用alert
}
};
接下来我们在webpack.config.js
配置loader
{
test: /\.js$/,
exclude: resolve(__dirname, 'node_modules'),
enforce: "pre", // 优先执行
loader: 'eslint-loader',
options: {
// 自动修复
fix: true
}
}
// 测试一下,写入有问题的代码
var createHeading = function createHeading() {
let element = document.createElement('h1');
element.textContent = 'Hello Webpack';
element.className = 'title';
return element;
};
let obj = { a: 1}
var no_camelcased = () => {
console.log('大白菜');
};
var dosomeing = () => {
// ...
alert(5)
};
const add = function add(a, b) {
return a + b
}
export { createHeading, add }
//
执行 yarn serve
然后会提示一系列的ESlint
语法检查, 我们只需将有问题的再次修改就行了
Hot Module Replacement
HMR
模块热替换devServe
中配置hot: true
就默认开启热更新了HMR
,在style-loader
内部实现了JS
文件: 默认不能使用HMR
功能HMR webpack-dev-server --hot
也可通过配置文件开启entry
入口,将HTML
文件引入// entry: ['./src/js/index.js', './src/index.html']
const webpack = require('webpack')
devServer: {
hot: true
}
plugins: [
new webpack.HotModuleReplacementPlugin()
]
// js
if (module.hot) {
// 一旦module.hot 为true 说明开启了HMR功能
// 让HMR功能代码生效
module.hot.accept('./heading', () => {
console.log('文件更新了');
});
}
多入口
entry: {
// 多入口
main: './src/js/index.js',
test: './src/js/test.js'
}
// 输出
output: {
filename: '[name].[contenthash:10].js', // 输出文件名
// __dirname是node.js的变量,代表当前文件目录绝对路径
path: resolve(__dirname, 'build') // 输出路径
},
// 重新打包
// main.67a94b6142.js
// test.9fd198e20a.js
// 缺点 不灵活
optimization
可以将node_modules
中的代码单独打包一个chunk
最终输出 自动分析多入口chunk
中,有没有公共的文件,如果有会打包成单独一个chunk
// 会输出多个js 文件代码
optimization: {
splitChunks: {
chunks: 'all'
}
}
配置文件根据环境不同导出不同配置
webpack.common.js
webpack.dev.js
webapack.prod.js
安装 yarn add wenpack-merge --dev
yarn webpack --config webpack.prod.js // 生产环境
const common = require('./webpack.common)
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const { CopyWebpackPlugin } = require('copy-webpack-plugin')
module.exports = merge(common, {
mode: 'production',
plugins: [
]
})