Webpack 进阶用法

Webpack 进阶用法

当前构建时的问题

  • 每次构建的时候不会清理目录,造成构建的输出目录output文件越来越多
通过npm script清理构建目录(并不优雅的处理方式)
  • rm -rf ./dist && webpack
  • rimraf ./dist && webpack
自动清理构建目录
  • 避免构建前每次都需要手动删除dist

  • 使用clean-webpack-plugin

    • 默认会删除output指定的输出目录
  • plugins:[
    	new CleanWebpackPlugin()
    ]
    

CSS增强

CSS兼容添加前缀
  • IE ==> Trident(-ms)
  • Geko(-moz) 火狐
  • WebKit(-webkit) 谷歌
  • Presto(-0)欧鹏

使用PostCSS插件autoprefixer自动补齐CSS3前缀

  • npm i postcss-loader autoprefixer -D

  • 使用autoprefixer插件

  • 根据Can I Use规则 https://caniuse.com/

  • module :{
            rules:[           
                {
                    test:/.less$/,
                    use:[
                        'style-loader',
                        'css-loader',
                        'less-loader',
                        {
                        	loader:'postcss-loader',
                        	  //参数
                        	  options:{
                        	 	plugins:()=>{
                        	 	//引入
                        	 		require('autoprefixer')({
    					//可以设置 autoprefixer  兼容浏览器版本
    					//>1% 使用人数占比
    					//ios7 兼容ios7版本以上 版本
                        browsers:['last 2 version','>1%,'ios7']
                        	 		})
                        	 	}
                        	}
                        }
                    ]
                },
             
    
            ]
        }
    
将移动端CSS px自动转换成rem
CSS媒体查询实现 响应式布局
  • 缺陷:需要写多套适配样式代码
使用px2rem-loader
  • 页面渲染时计算根元素的font-size
    • 可以使用手淘的lib-flexible
    • github.com/amfe/lib-flexible
module :{
        rules:[           
            {
                test:/.less$/,
                use:[
                    'style-loader',
                    'css-loader',
                    'less-loader',
                    {
                    	loader:'postcss-loader',
                    	  //参数
                    	  options:{
                   			remUnit:75,
                            remPrecision:8//转换成rem 后面的小数点位数
                    	}
                    }
                ]
            },        
        ]
    }
资源内联的意义
  • 代码层面
    • 页面框架的初始化脚本
    • 上报相关打点
    • css内联避免页面闪动
请求层面:减少http网络请求数
  • 小图片或者字体内联(url-loader
HTML 和 JS内联
  • raw-loader内联htmljs 安装版本为:npm i raw-loader@0.5.1 -D
css内联
  • 方案一:借助style-loader
  • 方案二:html-inline-css-webpack-pulugin
module :{
        rules:[           
            {
                test:/.less$/,
                use:[                    
                    {
                    loader:'style-loader',
                    //参数
                        options:{
                            inserAt:'top',//样式插入到`<head>`
                            singleton:true,//将所有的`style`标签合并成一个
                        }
                    }
                    'css-loader',
                    'less-loader',
                ]
            },        
        ]
    }

多页面应用(MPA)概念

每一次页面跳转得时候,后台服务器都会返回一个新的html文档,这种类型得网站也就是多页网站,也叫做多页应用

多页面打包基本思路

每个页面对应一个entry,一个html-webpack-plugin

缺点:每次新增或删除页面需要修改webpack配置

module.exports = {
	entry :{
		index:'./src/index.js',
		search:'./src/search.js'
	}
}

动态获取entry和设置 html-webpack-plugin数量

利用 glob.sync

  • entry:glob.sync(path.join(_dirname,'./src/*/index.js'))
module.exports = {
	entry :{
		index:'./src/index/index.js',
		search:'./src/search/index.js'
	}
}

//约定:把所有得页面都放在 src 目录下面,每个页面得人口文件都命名为index.js文件
  • 通过glob多页面打包
npm i glob
const glob = require('glob')

const setMPA = () =>{
	const entry = {};
	const htmlWebpackPlugins = [];
	const entryFiles = glob.sync(path.join(__dirname,'./src/*/'));//匹配src目录下所有页面内容
	Object.keys(entryFiles).map(index=>{
		const entryFire = entryFiles[index];
		const match = entryFiles.mach(/src\(.*)\/index\.js/)
		const pageName = match && match[1]
		entryFiles[pageName] = entryFiles;
		htmlWebpackPlugins.push(
            new HtmlWebpackPlugin({
            template:path.join(_dirname,`src/${pageName}/index.html`),
            filename:`${pageName}.html`, //指定打包出来之后得文件名称
            chunks:['search'],
            inject:true,
            minify:{
                html:true,
                collapseWhitespace:true,
                preserveLineBreaks:false,
                minifyCSS:true,
                minifyJS:true,
                removeComments:false
            }
        })
	})
	return {
		entry,
		htmlWebpackPlugins
	}
}
使用source map

作用:通过source map定位到源代码

开发环境开启,线上环境关闭

  • 线上排查问题得时候可以将sourcemap上传到错误监控系统
source map关键字
  • eval:使用eval包裹模块代码
  • source map:产生.map文件
  • cheap:不包含列信息
  • inline:将.map作为DataURL嵌入,不单独生成.map文件
  • module:包含loadersourcemap
提取页面公共资源
基础库基础
思路:将react 、 react-dom基础包通过引入cdn引入,不打入bundle
方法:使用html-webpack-externals-plugin
利用SplitChunksPlugin进行公共脚本分离
  • Webpack4内置的,替代CommonsChunkPlugin插件
  • chunks参数说明:
    • async异步引入的库进行分离(默认)
    • initial:同步引入的库进行分离
    • all:所有引入的库进行分离(推荐)
module.exports = {
	optimization:{
		splitChunks:{
			chunks:'async',
			minSize:30000,
			maxSize:0,
			minChunks:1,
			maxAsyncRequests:5,
			maxInitialRequests:3,
			automaticNameDelimiter:'~',
			name:true,
			cacheGroups:{
				vendors:{
					test:/[\\/]node_modules[\\/]/,
					priority:-10
				}
			}
		}
	}
}
利用**SplitChunksPlugin**分离基础包

test:匹配出需要分离的包

module.exports = {
  //...
  optimization: {
    splitChunks: {
      cacheGroups: {
        commons: {
          test: /[\\/]node_modules[\\/]/,
   		  name:'vendors',
          chunks: 'all'
        }
      }
    }
  }
};
tree shaking(摇树优化)

概念:1个模块可能有多个方法,只要把其中的某个方法使用到了,则整个文件都会被达到bundle里面去,tree shaking 就是只把用到的方法打入bundle,没用到的方法会在uglify阶段被擦除掉

使用:webpack默认支持,在.babelrc里设置modules:false即可.production mode的情况下默认开启

要求:必须是ES6的语法,CJS的方式不支持

DCE (Elimination)

代码不会被执行,不可到达

代码执行的结果不会被用到

代码只会影响死变量(只写不读)

tree shaking原理

利用ES6模块的特点:

  • 只能作为模块顶层的语句出现
  • import模块名只能是字符串常量
  • import bindingimmutable

代码擦除:ugkify阶段删除无用代码

ScopeHoisting使用和原理分析

现象:构建后代码存在大量闭包代码

模块转换分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eoaFSTUg-1586446111477)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200408234303736.png)]

结论:

  • webpack转换后的模块会带上一层包裹
  • import会被转换成__webpack_require
进一步分析webpack的模块机制

分析:

  • 打包出来的是一个llFE(匿名闭包)
  • modules是一个数组,每一项是一个模块初始化函数
  • __webpack_require用来加载模块,返回module.exports
  • 通过WEBPACK_REQUIRE_METHOD(0)启动程序
scope hoisting原理

原理:将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量以防止变量名冲突

对比:通过scope hoisting可以减少函数声明代码和内存开销

scope hoisting

webpack modeproduction默认开启

必须是ES6语法,CJS不支持

代码分割得意义

对于大得web应用来说,将所有的代码都放在一个文件中显然是不够有效的,特别是当你的某些代码块实在某些特殊的时候才会被用到,webpack有有一个功能就是将你的代码库分割成chunks(语块),当代码运行到需要它们的时候在在加载

适用的场景:

  • 抽离相同代码到一个共享块
  • 脚本懒加载,是的初始下载的代码更小
懒加载JS脚本的方式

ComonJS:require.ensure

ES6:动态import(目前还没有原生支持,需要babel转换)

如何使用动态import
安装babel插件

npm install @babel/plugin-syntax-dynamic-import --save-dev

{
	"plugins":["@babel/plugin-syntax-dynamic-import"]
}
webpackESLint结合

安装husky

npm i husky --seve-dev

增加npm script,通过lint-staged增量检查修改的文件

"script":{
	"precommit":"lint-staged"	
},
"lint-staged":{
	"linters":{
		"*.{js.scss}":["eslint--fix","git add"]
	}
}

新建项目 时候 webpackESLint集成
  • 使用eslint-loader,构建时检查JS规范
module.exports = {
  //...
  module: {
    rules: {
  	 {
  	 	test:/\.js$/,
  	 	exclude:/node_modules/,
  	 	use:[
  	 		"babel-loader",
  	 		"eslint-loader"
  	 	]
  	 }
    }
  }
};
webpack打包库和组件

webpack除了可以用来打包应用,也可以用来打包JS

实现一个大整数加法库的打包
  • 需要打包压缩版和非压缩版本
  • 支持AMD / CJS / ESM模块引入
    • ESM=>import * as test from 'test'
    • CJS =>const test = require('test')
    • AMD =>require(['test'],function(test){ // ...})
如何将库暴露出去
  • library:指定库的全局变量
  • libraryTarget:支持库引入的方式
module.exports = {
	mode:'none',
	entry :{
		"large-number":'./src/index/index.js',
		"large-number.min":'./src/search/index.js'
	},
	output:{
		filename:"[name].js",
		library:'largeNumber',
		libraryExport:'default',
		libraryTarget:'umd'
	},
	optimization:{
		minimize:true,
		minimizer:[
			new TerserPlugin({
				include:/\.min\.js$/  //通过include 设置只压缩 min.js 结尾的文件
			})
		]
	}
}
设置人口文件

package.json 的 main字段为 index.js main:index.js

if(process.env.NODE_ENV === "production"){
	module.exports = require("./dist/large-number.min.js")
}else{
	module.exports = require("./dist/large-number.js")
}
webpack实现ssr打包
服务端渲染ssr是什么

渲染:HTML + CSS + JS +Data==>渲染后的HTML

服务端:

  • 所有模板等资源都存储在服务端
  • 内网机器拉取数据更快
  • 一个HTML返回所有数据
浏览器和服务器交互流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lqQvoiaX-1586446111479)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200409222304222.png)]

客户端渲染 vs服务端渲染

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oMGMtNN9-1586446111480)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200409222548020.png)]

总结:服务端渲染(SSR)的核心是减少请求

ssr的优势
  • 减少白屏的时间
  • 对于SEO友好
SSR代码实现思路
  • 服务端
    • 使用react-dom / serverrenderToString方法将React组件渲染成字符串,因为在服务端是没有window这些对象
    • 服务端路由返回对应的模板
  • 客户端
    • 打包出针对服务端的组件
webpack ssr打包存在的问题
浏览器的全局变量(Node.js中没有document,window
  • 组件适配:将不兼容的组件根据打包环境进行适配
  • 请求适配:将fetch或者ajax发送请求的写法改成isomorphic-fetch或者axios
样式问题(Node.js无法解析css
  • 方案一:服务端打包通过ignore-loader忽略掉css的解析
  • 方案二:将style-loader替换成isomorphic-style-loader
如何解决SSR打包之后样式不显示的问题

使用打包出来的浏览器端html为模板

设置占位符,动态插入组件

比如 iview table 在查看网页源代码之后会出现很多<!---->,就是占位从而显示样式

首屏数据如何处理

服务端获取数据

替换占位符

优化构建时命令行的显示日志

统计信息 stats

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g0kvygEF-1586446111481)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200409230846573.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q84SZkaE-1586446111482)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200409231203671.png)]

如何判断构建是否成功

CI / CDpipline 或者发布系统需要知道当前构建状态

每次构建完成后输入echo $ 获取错误吗

构建异常和中断处理

webpack4之前的版本构建失败不会抛出错误码(error code

Node.js中的process.exit规范

  • 0 表示成功完成,回调函数中,err为null

  • 非0 表示执行失败,回调函数中,err 不为nullerr.code就是传给exit的数字

如何主动捕获并处理构建错误

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OPuMUzFL-1586446111483)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200409232612853.png)]

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值