webpack学习笔记

46次阅读

共计 6733 个字符,预计需要花费 17 分钟才能阅读完成。

简介

webpack 可以做的事

代码转换
文件优化
代码分割
模块合并
自动刷新
代码校验
自动发布

面试常见考点

webpack 常见配置

webpack 高级配置

ast 抽象语法树

webpack 中的 Tapable

掌握 webpack 流程,手写 webpack

手写 webpack 中常见的 loader

手写 webpack 中常见的 plugin

webpack 基础配置
起步

创建 src—>index.js

npx webpack
基础配置

//webpack 是 node 写出来的,所以需要 node 的写法

let path = require(‘path’) // 核心模块

module.exports = {
mode: ‘development’, // 默认两种:production development
entry: ‘./src/index.js’, // 入口
output: {// 出口
filename: ‘bundle.js’, // 打包后的文件名
path: path.resolve(__dirname, ‘dist’), //resolve 把相对路径解析成绝对路径,__dirname 意思是在当前目录建立一个,路径必须是一个绝对路径
}
}

script 脚本

手动配置:npx webpack –config webpack.config.js

脚本配置:

“scripts”: {
“build”: “webpack”
}

//npm run build
传参 npx webpack — –config webpack.config.js

Html 插件
npx webpack-dev-server

开发服务,内部通过 express 实现这种服务
并不真实打包文件,只是在内存中生成

htmlWebpackPlugin
将打包后的 js 文件插入 html 文件,并放到 build 目录下
let htmlWebpackPlugin = require(‘html-webpack-plugin’)

module.exports = {
devServer: {// 开发服务器的配置
port: 3000, // 设置端口号
progress: true, // 进度条
contentBase: ‘/.build’, // 指定静态目录
compress: true
},
output: {
filename: ‘bundle.[hash:8].js’, // 文件名
path: path.resolve(__dirname, ‘dist’),
},
plugins: [// 数组 放着所有的 webpack 插件
new htmlWebpackPlugin({
template: ‘./src/index.html’, // 模板
filename: ‘index.html’, // 打包后的文件名
minify: {// 打包后的 html 也压缩
removeAttributeQuotes: true, // 删除属性的双引号
collapseWhitespace: true, // 折叠空行
},
hash: true //html 文件加上哈希戳
})
]
}

css 配置

loader:Webpack 本身只能处理 JavaScript 模块,如果要处理其他类型的文件,就需要使用 loader 进行转换。Loader 可以理解为是模块和资源的转换器,它本身是一个函数,接受源文件作为参数,返回转换的结果

css 配置

css-loader 解析 @import 这种语法

style-loader 把 css 插入到 head 的标签中

loader 的特点: 希望单一

loader 的用法: 字符串只用一个 loader,多个 loader 需要 []

loader 的顺序: 默认是从右向左执行       从下往上

优先级
{
loader: ‘style-loader’,
options: {
insertAt: ‘top’ // 确保优先级
}
}
处理 less、sass、stylus

yarn add less less-loader
yarn add node-sass sass-loader
yarn add stylus stylus-loader

module.exports = {
module: {// 模块
rules: [// 规则
//loader 的特点: 希望单一
//{test: /\.css$/, use: [‘style-loader’, ‘css-loader’] } // 第一种: 写法
//loader 还可以写成对象方式
{
// 处理 less 文件
test: /\.css$/,
use: [{
loader: ‘style-loader’,
options: {
insertAt: ‘top’ // 确保优先级
}
},
‘css-loader’, //@import 解析路径
‘less-loader’ // 把 less —->css
]
}
]
}
}
抽离 CSS 的插件

默认打包后只能插入 <style> 标签内,我们希望抽离成 <link> 形式
通过 mini-css-extract-plugin 这个插件
yarn add mini-css-extract-plugin -D
插件都是类,插件的使用顺序没有先后

let MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)

// 配置 plugin
plugins: [
new MiniCssExtractPlugin({
filename: ‘main.css’,
})
],

// 配置 module
module: {
rules: [{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, ‘css-loader’]
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, ‘css-loader’, ‘less-loader’]
}
]
}
自动添加前缀

autoprefixer
前提要用 postcss-loader

yarn add postcss-loader autoprefixer

// 配置 module
// 先处理 post-css 再处理 css
module: {
rules: [{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, ‘css-loader’,’postcss-loader’] // 加上 post-css
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, ‘css-loader’, ‘postcss-loader’, ‘less-loader’]
}
]
}
// 创建 postcss.config.js 文件并配置

module.exports = {
plugins: [require(‘autoprefixer’)]
}
压缩 css(同时保证 js 的压缩)

通过 optimize-css-assets-webpack-plugin

yarn add optmize – css – assets – webpack – plugin – D
uglifyjs-webpack-plugin

let path = require(‘path’)
let htmlWebpackPlugin = require(‘html-webpack-plugin’)
let MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
let OptimizeCss = require(‘optimize-css-assets-webpack-plugin’)
let UglifyJsPlugin = require(‘uglifyjs-webpakc-plugin’)

module.exports = {
Optimization: {//*** 优化项,用了这个插件之后就必须用一下 Uglifyjs 压缩 js
minimizer: [
new UglifyJsPlugin({
cache: true, // 是否用缓存
parallel: true, // 是否并行打包
sourceMap: true
}),
new OptimizeCss()
]
},
devServer: {
port: 3000,
progress: true,
contentBase: ‘/.build’
},
mode: ‘development’,
entry: ‘./src/index.js’,
output: {
filename: ‘bundle.[hash:8].js’,
path: path.resolve(__dirname, ‘dist’),
},
plugins: [
new htmlWebpackPlugin({
template: ‘./src/index.html’,
filename: ‘index.html’,
minify: {
removeAttributeQuotes: true,
collapseWhitespace: true,
},
hash: true
}),
new MiniCssExtractPlugin({
filename: ‘main.css’
})
],
module: {
rules: [
//{test: /\.css$/, use: [‘style-loader’, ‘css-loader’] }
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, //*** 创建 link 标签, 引用
‘css-loader’,
‘less-loader’,
‘postcss-loader’

]
}
]
}
}

JS 配置
转化 es6 语法
babel

yarn add babel-loader @babel/core @babel/preset-env -D
配置 module

module: {
rules: [{
test: /\.js$/,
use: {
loader: ‘babel-loader’,
options: {// 用 babel-loader es6—->es5
presets: [
‘@babel/preset-env’
]
}
}
}
]
}

配置提案里支持的语法
class A{
a = 1;
}
yarn add @babel/plugin-proposal-class-properties -D
{
test: /\.js$/,
use: {
loader: ‘babel-loader’,
options: {
presets: [
‘@babel/preset-env’
],
plugins: [
‘@babel/plugin-proposal-class-properties’
]
}
}
}
支持装饰器语法
function log(target) {
console.log(target, ’23’)
}

log(A)
yarn add @babel/plugin-proposal-decorators -D
配置 module

module: {
rules: [{
test: /\.js$/,
use: {
loader: ‘babel-loader’,
options: {// 用 babel-loader es6—->es5
presets: [
‘@babel/preset-env’
],
plugins: [
[‘@babel/plugin-proposal-class-properties’],
[‘@babel/plugin-proposal-decorators’,{“legacy”:true}],
[‘@babel/plugin-transform-runtime’]
]
}
}
}
]
}
处理 JS 语法及校验
function *gen(params){
yield 1;
}
console.log(gen().next()); // 内置 API

// Uncaught ReferenceError: regeneratorRuntime is not defined

babel-runtime

yarn add @babel/plugin-transform-runtime -D
yarn add @babel/runtime

module: {
rules: [{
test: /\.js$/,
use: {
loader: ‘babel-loader’,
options: {// 用 babel-loader es6—->es5
presets: [
‘@babel/preset-env’
],
plugins: [
[‘@babel/plugin-proposal-class-properties’], [‘@babel/plugin-proposal-decorators’,{“legacy”:true}],
[‘@babel/plugin-transform-runtime’]
]
}
},
include:path.resolve(__dirname,’src’), // 包括查找范围
exclude:/node_module/ // 排除查找范围
}
]
}
@babel/polyfill
‘aaa’.include(‘a’) //ES7 语法

// 实例上的方法默认都不会解析
yarn add @babel/polyfill
//a.js
require(‘@babel/polyfill’)
‘aaa’.include(‘a’)
eslint
yarn add eslint eslint-loader
module: {
rules: [//loader 默认从右向左执行 从下到上,写的太多容易乱,写到一起删除不方便
{
test:\.js$/,
use:{
loader:’eslint-loader’,
options:{
enforce:’pre’ //previous -> normal-> post 顺序执行
}
}
}
/*…*/
]
}

选择好配置, 下载.eslintrc.json 到 configuration

全局变量引入问题

第三方模块引用
yarn add jquery

import $ form ‘jqurey’
console.log($)
console.log(window.$) //undefined, 并不会挂载到 window 上
如何将变量暴露给 window?

expose-loader (内联 loader)
yarn add expose-loader
import $ from ‘expose-loader?$!jquery’ // 将 jquery 作为 $ 暴露给全局
也可以在 webpack.config.js 中配
module: {
rules: [{
test: require.resolve(‘jquery’),
use: ‘expose-loader?$!jquery’
}
]
}
在每个模块中注入 $ 对象
//webpack.config.js
let Webpack = require(‘webpack’)
new Webpack.ProvidePlugin({
// 再每个模块中都注入 $ 符
jqurey: ‘$’
})
//index.js
console.log($) // 只是在每个模块中都注入一个 `$`
// 此时 window.$ //undefined

cdn 外部路径引入
<script src=”https://cdn.bootcss.com/jquery/3.3.1/core.js”></script>
// 如果此时 js 也引入 jquery 会导致重复
import $ form jquery
externals: {
jquery: ‘jQuery’ // 告诉 webpack 从外部引入,并不需要打包,忽略
},
总结

expose-loader: 暴露到 window 上

providePlugin: 给每个提供一个
引入不打包

loader 类型

pre             前面执行的 loader

normal        普通的 loader

liader        内联 loader

post            后置 loader

图片处理
图片引入方式
在 js 中创建图片来引入
let image = new Image()
image.src = ‘./logo.png’
document.body.appendChild(image) // 打包完,其实就是一个普通的字符串,并没有真正的引入图片
file-loader

yarn add file-loader
默认在内部生成图片,到 build 目录下,并且把生成的路径的名字返回回来

//webpack.config.js

module: {
rules: [{
test: /\.(png|jpg|gif)$/,
use: ‘file-loader’
}
]
}
//index.js

import logo from ‘./logo.png’ // 把图片引入, 生成一个哈希戳的 logo,返回的结果是一个新的图片

console.log(logo)

let image = new Image();
image.src = logo;
document.body.appendChild(image)

在 css 中引入 background(‘url’)

<img src=”” alt=””>

打包文件分类
打包多页应用
配置 source-map

正文完
 0

webpack学习笔记

47次阅读

共计 3520 个字符,预计需要花费 9 分钟才能阅读完成。

1、什么是 webpack
模块打包工具:分析项目结构,找到 JS 模块以及其它的一些浏览器不能直接运行的语言(less 等),并将其打包为合适的格式以供浏览器使用。
2、webpack 核心概念
主要有 6 部分:

Entry : 输入入口,webpack 构建第一步从这里开始
Moudle:一个模块对应一个文件,从 entry 开始递归找到所有依赖的模块
Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割
Loader:模块转换器,将模块原内容按照需求转换成新内容
Plugin:扩展插件,在 Webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要的事情
Output:输出,在 Webpack 经过一系列处理并得出最终想要的代码后输出结果

3、webpack 的工作流程
项目当作一个整体,通过给定的主文件,webpack 从主文件开始找到项目所有依赖的文件,再用 loaders 处理这些文件,最后打包为一个浏览器可识别的 javascript 文件。
4、执行流程

递归解析 entry 依赖的所有 module;
每找到一个 module,根据配置的 loader 去找相应的转换规则;
对 module 进行转换后再解析当前 module 所依赖的 module;
这些模块以以恶搞 entry 为分组,以一个 entry 和依赖的 module 就是一个 chunk;
webpack 将所有 chunk 转换成文件输出,并在一定时候执行 plugin 逻辑。

5、配置
1、全局安装 webpack
$ sudo npm install -g webpack (全局安装)
2、创建 package.json 文件夹
$ npm init 在终端中使用命令可以自动创建这个 package.json 文件。输入这个命令后,终端会问你一系列诸如项目名称,项目描述,作者等信息,不过不用担心,如果你不准备在 npm 中发布你的模块,这些问题的答案都不重要,回车默认即可
3、在项目中安装 Webpack 作为依赖包
npm install –save-dev webpack
4、创建两个文件夹
app 文件夹和 public 文件夹,app 文件夹用来存放原始数据和我们将写的 JavaScript 模块,public 文件夹用来存放之后供浏览器读取的文件(包括使用 webpack 打包生成的 js 文件以及一个 index.html 文件)。接下来我们再创建三个文件:

index.html – 放在 public 文件夹中;

Greeter.js– 放在 app 文件夹中;

main.js– 放在 app 文件夹中;

5、在 index.html 中写入代码
目的在于引入打包后的 js 文件(这里我们先把之后打包后的 js 文件命名为 bundle.js)

6、在 Greeter.js 中写入代码
定义一个返回包含问候信息的 html 元素的函数, 并依据 CommonJS 规范导出这个函数为一个模块

7、在 main.js 中写入代码
用以把 Greeter 模块返回的节点插入页面
8、通过配置文件使用 webpack
定义一个配置文件,将所有与打包相关信息均放在配置文件中。新建 webpack.config.js 文件,写入配置信息,主要涉及到的内容是入口文件路径和打包后文件的存放路径。

有了这个配置之后,再打包文件,只需在终端里运行 webpack(非全局安装需使用 node_modules/.bin/webpack) 命令就可以 ]
9、更快捷的执行打包任务
可以通过在 package.json 中对 scripts 对象进行相关设置即可,设置方法如下:
![图片上传中 …]
配置后执行 npm start 即可进行快速打包
10、webpack 其他强大功能
(1)source mapssource maps 提供编译文件和源文件的对应。配置后,webpack 就可以在打包时为我们生成 source maps,这为我们提供了一种对应编译文件和源文件的方法,使得编译后的代码可读性更高,也更容易调试。在 webpack 的配置文件中配置 source maps,需要配置 devtool:

devtool 选项
配置结果

source-map
在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的 source map,但是它会减慢打包速度;

cheap-module-source-map
在一个单独的文件中生成一个不带列映射的 map,不带列映射提高了打包速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便;

eval-source-map
使用 eval 打包源文件模块,在同一个文件中生成干净的完整的 source map。这个选项可以在不影响构建速度的前提下生成完整的 sourcemap,但是对打包后输出的 JS 文件的执行具有性能和安全的隐患。在开发阶段这是一个非常好的选项,在生产阶段则一定不要启用这个选项;

cheap-module-eval-source-map
这是在打包文件时最快的生成 source map 的方法,生成的 Source Map 会和打包后的 JavaScript 文件同行显示,没有列映射,和 eval-source-map 选项具有相似的缺点;

对小到中型的项目,eval-source-map 是一个很好的选项,只应该开发阶段使用它,继续对上文新建的 webpack.config.js,进行如下配置:

(2) 构建本地服务器通过构建本地服务器,可以让浏览器监听代码修改,自动刷新修改后的结果,改构建基于 node.js,不过它是一个单独的组件,在 webpack 中进行配置之前需要单独安装它作为项目依赖。
npm install –save-dev webpack-dev-server
dev-server 的配置项如下所示:

devserver 的配置选项
功能描述

contentBase
默认 webpack-dev-server 会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录(本例设置到“public” 目录)

port
设置默认监听端口,如果省略,默认为”8080“

inline
设置为 true,当源文件改变时会自动刷新页面

historyApiFallback
在开发单页应用时非常有用,它依赖于 HTML5 history API,如果设置为 true,所有的跳转将指向 index.html

配置 dev-server 位置在 webpack.config.js 中,配置添加后如下图所示:

在配置好 dev-server 后还需要再 package.json 的 scripts 中配置运行命令,如下图所示:

(3)Loaders 通过使用不同的 loader,webpack 有能力调用外部的脚本或工具,实现对不同格式的文件的处理,比如说分析转换 scss 为 css,或者把下一代的 JS 文件(ES6,ES7) 转换为现代浏览器兼容的 JS 文件,对 React 的开发而言,合适的 Loaders 可以把 React 的中用到的 JSX 文件转换为 JS 文件。Loaders 需要单独安装,且配置在 webpack.config.js 中的 modules 关键字下进行配置,配置项:

test:匹配 loaders 所处理文件的拓展名的正则表达式(必须)
loader : loader 名称(必须)
include /exclude : 手动添加需要处理的文件(文件夹)或 屏蔽不需要处理的文件(文件夹)(可选)
query : 为 loader 提供额外的设置选项(可选)

(4)Babelbabel 是一个 js 编译平台,可以编译 ES6、ES7,也可使用 JSX 等语法安装 ES6 以及 JSX 解析包
// npm 一次性安装多个依赖模块,模块之间用空格隔开 npm install –save-dev babel-core babel-loader babel-preset-env babel-preset-react 在 webpack 中配置 babel:
(5)插件(Plugins)插件用于扩展 webpack。plugins 和 loaders 的区别:

loaders 是在打包构建过程中用来处理源文件的(JSX,Scss,Less..),一次处理一个;
plugins 插件并不直接操作单个文件,它直接对整个构建过程其作用。

插件的使用需要用 npm 安装,然后在 webpack 配置中 plugins 字段下添加实例:

打包后的文件就会添加版权声明。一些插件:

Hot Module Replacement 允许你在修改组件代码后,自动刷新实时预览修改后的效果。
HtmlWebpackPlugin 依据一个简单的 index.html 模板,生成一个自动引用你打包后的 JS 文件的新 index.html

问题记录:
1、在安装时提示没有权限

解决:mac 电脑有权限限制,需要使用 sudo 进行安装

正文完
 0