1.加强CSS的解析性能
2.tree shaking
3.scope hoisting
4.如何用webpack打包组件库或工具库
5.如何用webpack做server render
6.如何在webpack外面做prerender
主动清理构建目录
以后构建时的问题
每次构建的时候不会清理目录,造成构建的输入目录output文件越来越多。
解决方案:
1.通过npm scripts清理构建目录
rm -rf ./dist && webpack
rimref ./dist && webpack
2.主动清理构建目录
防止构建前每次都须要手动删除dist
应用clean-webpack-plugin,默认会删除output指定的输入目录
module.exports = {
plugis: [new CleanWebpackPluginn()]
}
PostCSS插件autopredfixer主动补充CSS3前缀
css3的属性为什么须要前缀?
Trident(-ms) Geko(-moz-) Webkit(-webkt) Presto(-o)
举个例子
.box{
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
-o-border-radius: 10px;
border-radius: 10px;
}
如何在编写Css不须要增加前缀?
应用autoprefixer主动补全css3前缀
应用autoprefixer插件
module.exports = {
module: {
rules: [
{test: /\.less$/, use: [
'style-loader',
'css-loader',
'less-loader',
{
loader: 'postcss-loader',
options: {
plugins: () => {
require('autoprefixer')({
browsers: ['last 2 version', "> 1%", "IOS 7"]
})
}
}
}
]}
]
}
}
主动转换rem
浏览器的分辨率不同(挪动设施风行之后,不同设施分辨率不同,特地是ios),须要前端进行大量的适配。
1.CSS媒体查问实现响应式布局
缺点:须要写多套适配款式代码
@media screen and (max-width: 980px) {
.header {
width: 900px;
}
}
@media screen and (max-width: 480px) {
.header {
width: 400px;
}
}
@media screen and (max-width: 350px) {
.header {
width: 300px;
}
}
rem是什么
W3C对rem的定义:font-size of the root element
rem和px的比照:
rem是绝对单位
px是相对单位
1.应用px2rem-loader将px转成rem
2.动静计算1rem等于多少px(font-size的值)
能够应用手淘的lib-flexible库
module.exports = {
module: {
rules: [
{test: /\.less$/, use: ['style-loader','css-laoder', 'less-loader',
{loader: 'px2rem-loader',
options: {
remUnit: 75,
remPrecision: 8
}
}
]}
]
}
}
资源内联
代码层面:
- 页面框架的初始化脚本
在下面主动转rem的例子中,如果咱们想要引入lib-flexible库,须要手动在index.html中引入代码,因为这段代码须要在页面加载之前执行 - 上报相干打点
css初始化和加载实现,js初始化和加载实现等等一些上报点的代码都须要内联到html去,而不能引入到脚本外面去。 - css内联防止页面闪动
将首屏的css内联到页面外面去
申请层面:缩小HTTP网络申请数
小图片或字体则内联
HTML和JS内联
raw-loader应用0.5.2的版本
<!DOCTYPE html>
<html lang="en">
<head>
<%=require('raw-loder!./meta.html')%>
<title>Document</title>
<script>
<%=require('raw-loder!babel-loader!../node_modules/lib-flexible/flexible.js')%>
</script>
</head>
<body>
<div id="root"></div>
</body>
</html>
raw-loader内联html
<script>${require('raw-loader!babel-loader!./meta.html')}</script>
raw-loader内联JS
咱们书写的JS脚本外面可能蕴含es6等高级语法,此时除了raw-loader之外还须要babel-loader,内联之前对他进行转换
<script>${require('raw-loader!babel-loader!../node_modules/lib-flexible')}</script>
CSS内联
计划一:借助style-loader,给他设置一个参数:singleton
module.exports = {
module: {
rules: [
{test: /\.scss$/,
use: [
{
loader: 'style-loader',
options: {
insertAt: 'top', // 将款式插入到<head>
singleton: true, // 将所有的style标签合并成一个
}
}
]}
]
}
}
计划二:html-inline-css-webpack-plugin
html-webpack-plugin默认应用的是ejs模板引擎,所以能够间接应用花括号的语法(不同版本会有差别)
多页面利用概念
多页面公布上线之后有多个入口,一个页面就是一个业务。
多页面利用的劣势,每个页面之间是解耦的,且对SEO更加敌对。每一次页面跳转的时候,后盾服务器都会返回一个新的html文档,这种类型的网站也就是多页网站,也叫做多页利用。
多页面打包基本思路
每个页面对应一个entry,一个html-webpack-plugin
毛病:每次新增或删除页面须要改webpack配置
module.exports = {
entry: {
index: './src/index.js', // 首页
search: './src/search.js' // 搜寻页
}
}
多页面打包通用计划
动静获取entry和设置html-webpac-plugin数量,然而这里须要一个约定(如果入口都放在src目录下)
module.exports = {
entry: {
index: './src/index/index.js',
search: './src/search/index.js'
}
}
利用glob.sync
npm i glob -D
entry: glob.sync(path.join(__dirname, './src/*/index.js'))
Source Map
source map是开发利器,在打包的时候会将源代码打包成bundle文件,bundle文件就是通过loader转换和插件解决了的,最初会生成一个大的js文件,这个文件在最初调试的时候是没方法的。
作用:通过source map定位到源代码
开发环境开启,线上环境敞开
线上排查问题的时候能够将sourcemap上传到谬误加农零碎
source map关键字
module.exports = {
devtool: 'source-map'
}
eval:应用eval包裹模块代码
source map:产生.map文件
cheap:谬误不蕴含列信息
inline:将.map作为DataURI嵌入,不独自生成.map文件内(map文件内联到js文件中去)
module:蕴含loader的sourcemap
source map类型
devtool | 首次构建 | 二次构建 | 是否适宜生产环境 | 能够定位的代码 |
---|---|---|---|---|
{none} | +++ | +++ | yes | 最终输入的代码 |
eval | +++ | +++ | no | webpac生成的代码(一个个的模块) |
cheap-eval-source-map | + | ++ | no | 通过loader转换后的代码(只能看到行) |
cheap-module-eval-source-map | + | ++ | no | 源代码(只能看到行) |
eval-source-map | — | + | no | 源代码 |
cheap-source-map | + | o | yes | 通过loader转换后的代码(只能看到行) |
cheap-module-source-map | o | – | yes | 源代码(只能看到行) |
inline-cheap-source-map | + | o | no | 通过loader转换后的代码(只能看到行) |
source-map | — | — | yes | 源代码 |
inline-source-map | — | — | no | 源代码 |
hidden-source-map | — | — | yes | 源代码 |
提取页面公共资源
页面之间存在公共模块,且他们应用的根底库是一样的,如果打包的适宜把公共模块都独自打一份,根底库也独自打一份,打包的体积会十分大,所以须要进行根底库的拆散和公共模块的拆散。
根底库拆散
思路:将react、react-dom根底包通过cdn引入,不打入bundle中
办法:应用html-webapck-externals-plugin
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin')
plugins: [
new HtmlWebpackExternalsPlugin({
externals: [
{
module: 'react',
entry: '//11.url.cn/now/lib/15.1.0/react-with-addons.min.js?_bid=3123',
global: 'React',
},
{
module: 'react-dom',
entry: '//11.url.cn/now/lib/15.1.0/react-dom.min.js?_bid=3123',
global: 'ReactDOM',
}
]
})
]
以上办法,将把react和react-dom从cdn引入,不会打包进来
利用SplitChunksPlugin进行公共脚本拆散
webpack4内置的,代替CommonsChunkPlugin插件
chunks参数阐明:
- async 异步引入的库进行拆散(默认)
- initial 同步引入的库进行拆散
- all 所有引入的库进行拆散(举荐)
module.exports = {
...
optimization: {
splitChunks: {
chunks: 'async',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequest: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test://,
priority: -10
}
}
}
}
}
test:匹配出须要拆散的包
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /(react|react-dom)/,
name: 'vendors',
chunks: 'all'
}
}
}
}
此时会把react和react-dom提取进去名字为vendors
利用SplitChunksPlugin拆散页面公共文件
minChunks:设置最小援用次数为2次(被援用2次则提取进去)
minuSize:拆散的包体积的大小(文件大小超过则提取)
module.exports = {
optimization: {
splitChunks: {
minSize: 0.
cacheGroups: {
commons: {
name: 'commons',
chunks:'all',
minChunks: 2,
}
}
}
}
}
Three Shaking(摇树优化)
概念:1个模块可能有多个办法,只有其中的办法应用到了,则整个文件都会被打到bundle外面去,tree shaking就是只把用到的办法打入bundle,没用到的办法会在uglify阶段被擦除掉。
应用:webpack默认反对,在.babelrc里设置modules: false即可,production mode的状况下默认开启
要求:必须是ES6的语法(import),CJS的形式不反对
DCE(Elimination)
代码不会被执行,不可达到
if(false){
console.log('这段代码永远不会执行')
}
代码执行的后果不会被用到
代码只会影响死变量(只写不读)
Three-Shaking原理
利用ES6模块的特点:
- 只能作为模块顶层的语句呈现
- import的模块名只能是字符串常量
- import bunding是immutable的
代码擦除:uglify阶段删除无用代码
Scope Hoisting应用和原理剖析
景象:构建后的代码存在大量闭包代码
会导致什么问题:
- 大量函数闭包包裹代码,导致体积增大(模块越多)
- 运行代码时创立的函数作用域变多,内存开销变大
模块转换剖析:
模块(index.js)
import {helloWorld} from './helloworld'
import '../../common'
document.write(helloWorld())
模块初始化函数(webpack打包后)
/* 0 */
/***/ (function(module,__webpack_exports__, __webpack_requie__) {
'use strict';
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _common_WEBPACK_IMPORTED_MODULE_0)) = __webpack_require__(1);
/* harmoney */ var _helloworld_WEPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
document.write(Object(__helloworld_WEBPACK_IMPORTED_MODULE_1__['helloworld'])())
}
论断:
- 被webpack转换后的模块会带上一层包裹
- import会被转换成__webpack_require
进一步剖析webpack的模块机制
(function(modules) {
var installModules = {}
function __webpack_require__(moduleId) {
if (installModules[moduleId])
return installModules[moduleId].exports
var module = installModules[moduleId] = {
i: moduleId,
l: false,
exports: {},
}
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
module.1 = true
return module.exports;
}
__webpack_require__(0);
})([
/* 0 module */
(function (module, __webpack_exports__, __webpack_require__) {
...
},
/* 1 module */
(function (module, __webpack_exports__, __webpack_require__) {
...
},
/* n module */
(function (module, __webpack_exports__, __webpack_require__) {
...
},
])
剖析:
- 打包进去的是一个IIFE(匿名闭包)
- modules是一个数组,每一项是一个模块初始化函数
- __webpack_require用来加载模块,返回module.exports
- 通过WEBPACK_REQUIRE_METHODS(0)启动程序
scope hoisting原理
原理:将所有模块的代码依照援用程序放在一个函数作用域里,而后适当的重命名一些变量以避免变量名抵触
比照:通过scope hoisting能够缩小函数申明代码和内存开销(将代码内联进来,同一个作用域上面,如果有多个变量,会导致命名抵触,会给这些适当的重命名。这样就缩小了内存的开销)
scope hoisting应用
webpack mode为production默认开启
必须是ES6语法,CJS(动静引入模块)不反对
module.exportss = {
plugins: [
new webpack.optimize.ModuleConcatenationPlugin()
]
}
总结:scope hoisting是把每个模块被webpack解决成的模块初始化函数整顿到一个对立的包裹函数里,也就是把多个作用域用一个作用域取代,以缩小内存耗费并缩小包裹块代码,从每个模块有一个包裹函数变成只有一个包裹函数包裹所有的模块,然而有一个前提就是,当模块的援用次数大于1时,这个成果就会有效
代码宰割的意义
对于大的web利用来将,将所有的代码都放在一个文件中显然是不够无效的,特地是当你的某些代码块是在某些非凡的时候才会被应用到。webpack有一个性能就是将你的代码库宰割成chunks(语块)当代码运行到须要他们的时候再加载。
实用的场景:
- 抽离雷同代码到一个共享块
- 脚本懒加载,使得初始下载的代码更小
懒加载JS脚本的形式
CommonJS:require.ensure(webpack提供的)
ES6:动静import(目前还没有原生反对,须要babel转换)
如何应用动静Import?
装置Babel
npm i @babel/plugin-syntax-dynamic-import --save-dev
ES6:动静import(目前还没有原生反对,须要babel转换)
.babelrc
{
plugins: ['@babel/plugin-syntax-dynamic-import']
}
loadComponent() {
import('./text.js').then((txt) => {
...
})
}
懒加载的脚本’text.js’会独自打包成一个js文件
在webpack中应用eslint
行业里优良的eslint标准实际
Airbnb:eslint-config-airbnb、eslint-config-airbnb-base
制订团队的eslint标准
遵循原则:
- 不要反复造轮子,基于eslint:recommend配置并改良
- 可能帮忙发现代码谬误的规定,全副开启
- 帮忙放弃团队的代码格调对立,而不是限度开发体验。![上传中…]()
发表回复