Webpack
webpack5原理与应用B站视频
为什么需要webpack?
不使用webpack时:
其一,需要加载多个js文件。缺点:多个js之间的依赖关系需要按顺序进行引入,扩展性低,局限性大;
其二,只加载一个继承了所有js文件代码的js文件。缺点:作用域问题(不同js绑定不同的变量,如jquery的$和loadash),文件太大,可读性差,可维护性弱。
解决作用域问题(早期GRUNT,GULP):
IIFE(immediately invoke function expression)立即执行函数表达式
;(function(){var name=1;return name;})();
如何代码拆分,只要加载需要用到的模块
module.exports = {module1,module2};
const a = require('./modules');
a.module1;a.module2;
require只适用于NodeJs,浏览器无法使用;
浏览器如何支持模块(早期browserify,reqiure.js)
add.js & minus.js:里面用define
现在的浏览器支持方式
const add=(x,y)=>{return x+y}
export default add;
<script type="module">
import add from '地址'
</script>
npx命令:当一个模块不存在时,会从网上先下载再执行
浏览器支持ECMAScript的模块不太好,且迭代太慢,所以要用webpack
webpack能干嘛
打包js应用程序,支持es的模块化和commomjs。扩展支持其他静态资源的打包,图片,字体,样式文件;
webpack竞品 Vite,Rollup,Parcel
如何解决作用域冲突(IIFE),如何代码拆分(模块化),如何让浏览器支持模块(require.js和es的模块化)
webpack应用
全局安装webpack(不推荐全局,会锁定某个版本;在团队协作在容易有差异。)
npm install webpack webpack-cli --global
//查看webpack版本
webpack -v
全新项目内安装webpack
npm init -y 使用默认配置生成
-y 的含义:yes的意思,在init的时候省去了敲回车的步骤,生成的默认的package.json
version 版本号,一般从0.1.0开始
description描述
keywords 关键词用逗号隔开
author名字加邮箱
license UNLICENSE,一般不授权公用
npm install webpack webpack-cli --save-dev
项目内安装‘开发’依赖
pwd 打印当前工作目录
//在项目文件夹内打包,此时的webpack时全局的webpack
webpack
//查看打包详情
webpack --status detailed
//使用项目内的webpack进行打包
①先卸载全局的webpack
npm uninstall webpack webpack-cli --global
②使用项目内的webpack进行打包
npx webpack //先在当亲目录找,没有就往上继续找
webpack.config.js配置
为什么用:命令行配置麻烦,且无法保存配置;
在项目目录下新建webpack.config.js。
运行时,webpack自动读取。
在nodejs中运行,使用了nodejs的commonjs模块,因此需要使用
const path = require('path')
module.exports = {
entry: './src/index.js',
mode: 'none',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, './dist')
}
}
麻烦:每次都要去index.html里面更新打包后的js地址。
插件来源:
社区(htmlWebpackPlugin),
webpack内置,
第三方;
使用HtmlWebpackPlugin
mode选项
取值:none,development,production
使用sourceMap进行调试
npm install html-webpack-plugin -D (--save-dev)
目前预览项目效果是通过访问当前index.html的地址
入口文件及其依赖变化时,webpack自动进行打包,但还是要手动刷新页面;
npx webpack --watch
webpack热更新:使用webpack -dev-server进行页面的更新(重新加载);webpack --watch只是为了自动打包。
不监听webpack.config.js
//安装,作为开发依赖进行安装到本地
npm install webpack-dev-server -D
删除dist后,无发访问dist文件夹,但还是能访问到内部的html文件;
资源模块asset module(webpack内置资源模块):允许使用webpack来打包其他资源文件。字体,图片,样式等。
资源模块类型asset module type:通过四种资源模块类型来替换所有loader
asset/resource:发送单独文件并导出url(生成文件)
asset/inline:导出资源的URI (不生成文件,生成dataURI并填入要用的地方)
asset/source :导出资源的源代码(不生成文件)
asset:选择发送单独文件(resource)还是导出资源的URI(inline)
npx webpack-dev-server --open
Loader
什么是Loader:webpack只能理解js和json这样的文件;loader可以让webpack解析其它类型的文件。
使用loader加载css代码
npm install css-loader -D
import './style.css'
document.body.classList.add('hello')
抽离和压缩css
npm install mini-css-extrace-plugin -D
npm install css-minimizer-webpack-plugin
加载字体
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource'
}
加载数据
CSV,TSV
npm install csv-loader
npm install xml-loader
babel -loader
为什么需要babel-loader:将ES6->ES5,将es6转换成低版本浏览器能够运行的es5
babel-loader:webpack里应用babel解析ES6的桥梁
@babel/core:babel核心模块
@babel/preset-env:babel的预设,一组babel插件的集合
npm install babel-loader @babel/core @babel/preset-env -D
缺少regeneratorruntime插件
npm install @babel/runtime -D
npm install @babel/plugin-transform-runtime -D
代码分离(抽离重复代码;加快首屏加载;)
入口起点:使用entry配置手动地分离代码;共用的文件会被重复打包
防止重复:使用Entry dependencies或者splitChunksPlugin(抽离静态代码import…from…关键字)去重和分离代码
动态导入:通过模块的内联函数(import)来分离代码;可以进行懒加载(用到再加载);
const btn = document.createElement('button')
btn.textContent = '点击运行'
btn.addEventListener('click', () => {
import('./math.js').then(({ add }) => {
console.log(add(1, 2))
})
})
document.body.appendChild(btn);
splitChunksPlugin和动态导入(import方法导入模块)一起使用实现动静态代码抽离
实践:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l3HwEo50-1643037187254)(C:\Users\a1808\AppData\Roaming\Typora\typora-user-images\image-20220115020617736.png)]
魔法注释(动态分离)
为用import(‘…’)方法引入的模块,进行分包时命名。
import('lodash').then(({add})->{})
import('lodash').then(({add})->{})
预加载(使用魔法注释配置webpackPrefetch:true;)
import('lodash').then(({add})=>{})
预获取:如若配置webpackPreload:true,则效果类似懒加载;
通过link标签来引入资源到index.html(再所有资源加载完成后,网络空闲时,进行加载)
下图为预获取
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OOapQ8ZD-1643037187256)(C:\Users\a1808\AppData\Roaming\Typora\typora-user-images\image-20220116015350259.png)]
import('lodash').then(({add})=>{})
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CSSMinimizerWenpackPlugin = require('css-minimizer-webpack-plugin')
const toml = require('toml')
const yaml = require('yaml')
const json5 = require('json5')
const path = require('path')
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, './dist'),
clean: true,
assetModuleFilename: 'images/[contenthash][ext]'
},
mode: 'development',
devtool: 'inline-source-map',
plugins: [
new HtmlWebpackPlugin({
template: './index.html',
filename: 'app.html',
inject: 'body'
}),
new MiniCssExtractPlugin({
filename: 'style/mystyle.css',
})
],
devServer: {
static: './dist',
open: true
},
module: {
rules: [{
test: /\.png$/,
type: 'asset/resource',
generator: {
}
},
{
test: /\.jpg$/,
type: 'asset/inline'
},
{
test: /\.txt$/,
type: 'asset/source'
}, {
test: /\.jpeg$/,
type: 'asset',
parser: {
dataUrlCondition:
{ maxSize: 4 * 1024 * 1024 }
}
},
{
test: /\.(css|scss)$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource'
},
{
test: /\.(csv|tsv)$/,
use: 'csv-loader'
},
{
test: /\.xml$/,
use: 'xml-loader'
},
{
test: /\.toml$/,
type: 'json',
parser: {
parse: toml.parse
}
},
{
test: /\.yaml$/,
type: 'json',
parser: {
parse: yaml.parse
}
},
{
test: /\.json5$/,
type: 'json',
parser: {
parse: json5.parse
}
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
[
'@babel/plugin-transform-runtime'
]
]
}
}
}
]
},
optimization: {
minimizer: [
new CSSMinimizerWenpackPlugin()
],
}
}
|