01 自动补齐css的前缀:保证浏览器的兼容问题。需要使用autoprefixer插件和postcss-loader。
webpack.config.js文件中的代码:
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']
})]
}
}
]}
]
}
}
02 移动端css :px自动转化为rem;使用px2rem-loader,同时需要引入手淘的lib-flexible库来完成
webpack.config.js文件中的代码:需要安装npm i px2rem-loader; npm i lib-flexible -s;
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']
})]
}
},
{
loader:'px2rem-loader',
options:{
remUnit:75, 1rem相当于75px 为设计稿的10分之一,配置完会把所有的px转化为rem
remPrecision:8 转化为rem后面保留的小数
}
}
]}
]
}
}
再然后在项目中index.html 导入 手淘的插件
03 资源内联:页面框架的初始化脚本,上报相关打点,css内联避免页面闪动, 减少http请求。
html与js的内联:
在index.html页面中的<head>头部引入
<script>${require('raw-loader!./meta.html')}</script>
<script>${require('raw-loader!babel-loader!../node_modules/lib-flexible.js')}</script>
css内联 方案一 借助style-loader;
rules:[{
test:'/\.scss$/',
use:[{
loader:'style-loader',
options:{
insertAt:'top', 样式插入到<head>
singleton:true 将所有style标签合并成一个
}
}]
}]
css内联 方案二 html-inline-css-webpack-plugin
04 多页面应用打包通用的方案需要动态获取entry和设置html-webpack-plugin的数量,用glob.sync
多页面的入口:entry是一个对象,对应不同的入口文件列入下面:
entry:{
index:'./src/index/index.js',
search:'./src/search/index.js'
}
所以得出的规律就是将所有的入口文件放置在src目录下利用脚本自动去进行加载src下的index.js文件
安装glob:npm i glob -D;
在webpack.config.js文件中执行如下的代码:
const glob = require('glob')
const setMPA = ()=>{
const entry = {} 入口文件
const htmlWebpackPlugins = [] 多个要渲染的模板
const entryFiles = glob.sync(path.join(__dirname,'./src/*/index.js'))
Object.keys(entryFiles).map((index)=>{
const entryFile = entryFiles[index]
const match = entryFile.match(/src\(.*)\/index\.js/)
const pageName = match[1]
entry[pageName] = entryFile
htmlwebpackPlugins.push(
new HtmlWebpackPlugin({
template:path.join(__dirname,`src/${pageName}/index.html`),
filename:`${pageName}.html`,
chunks:[pageName]
})
)
})
return {entry, htmlWebpackPlugins}
}
05 使用source map定位到源代码,开发环境开启,线上环境关闭。
在webpack.config.js配置文件中进行添加:
module.exports = {
devtool:'source-map'
}
06 提取页面公共资源:
基础库分离:
打包的时候,因为需要打包react react-dom等,导致打包的速度会变慢;
解决思路:将react react-dom基础包通过cdn引入,不打入到bundle中
方法:使用 html-webpack-externals-plugin,利用SplitChunksPlugin分离页面公共文件
使用步骤、
第一步 安装 npm i html-webpack-externals-plugin;
第二步 在webpack.config.js文件中导入htmlWebpackExternalsPlugin
第三步 在plugins:[
new HtmlWebpackExternalsPlugin({
externals:[
{
module:'react',
entry:'这里是cdn react的地址',
global:'React'
},
{
module:'react-dom',
entry:'这里是cdn reactdom的地址',
global:'ReactDOM'
}
]
})
]
第四步 在index.html页面中 通过script标签再导入react和reactDom的CDN的地址;
将页面中多个页面引入的文件打包到dist目录下。配置方法如下:
module.exports = {
optinization:{
splitChunks:{
minSize:0,
cacheGroups:{
commons:{
name:'commons',
chunks:'all',
minChunks:3 , //至少引入三次才回打包出来
}
}
}
}
}
这里需要在 new HtmlWebpackPlugin({chunks:['vendors',pageName]})添加vendors
07 tree shaking的作用:将项目中定义的方法和变量,实际并没有使用,排除在打包的目录下。
在项目中我们经常会定义一些变量或者方法,在项目中实际并没有被使用,那么在项目打包的使用同时也会将这些没有被使用的变量和方法进行一起打包,这样会造成代码的体积变大。
解决方法:在项目打包的时候将没有被使用到的方法和变量不被打包到dist目录下。
使用步骤: 在webpack.config.js文件中,如果mode模式是production的时候会自动开启tree Shaking的,
不会将没有被使用到的变量和方法打包到dist目录下
08 scope hoisting:必须是ES6的导入,CJS不支持。
原理:将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量以防止变量名的冲突
通过 scope hoisting 可以减少函数声明代码和内存开销
当mode为production的时候会默认开启scope hoisting
09 懒加载js脚本的方式;
ES6:动态import(目前还没有原生的支持,需要babel转换)
首先需要安装babel插件: npm install @babel/plugin-syntax-dynamic-import --save-dev;
将babel插件放在.babelrc的文件中:{'plugins':['@babel/plugin-syntax-dynamic-import']}
使用方法如下:
第一步 首先创建一个需要加载的组件比如:text.js代码如下
import React from 'react'
export default ()=>{<div>测试的组件</div>}
第二步index.js组件中动态的加载text这个组件,比如在点击div元素后进行加载;
import React from 'react'
class Index extends React.Component {
constructor(){
super(...arguments)
this.state = {Text:null}
}
render(){
const loadAsync = ()=>{
import('./text.js').then(res=>{
this.setState({Text:res.default})
})
}
return <div>
<div onClick={loadAsync}>异步加载test组件</div>
<span>{Text}</span> // 异步使用组件
</div>
}
}
10 在webpack中使用eslint
第一步 项目中安装相关的eslint的插件:
npm i eslint eslint-plugin-import eslint-plugin-react eslint-plugin-jsx-ally -D
npm i eslint-loader babel-eslint eslint-config-airbnd -D
第二步 在webpack.config.js文件中进行配置
module.exports = {
module:{
rules:[
{test:/.js$/,
use:['babel-loader','eslint-loader']
}
]
}
}
第三步 创建eslint配置文件 .eslintrc.js
module.exports = {
"parser":"babel-eslint",
"extends":"airbnd",
"env":{"browser":true,"node":true},
"rules":{
"semi":"error"
}
}
11 webpack打包组件和打包库,可以将打包完的组件库发布到npm上面去
要求:封装一个求大数的方法,这个方法可以通过es6和componentJs引入,同时需要打包正常的版本,和压缩的两个版本。
实现思路:
第一步 通过npm init -y; 创建一个项目
第二步 安装npm i webpack webpack-cli
第三步 创建src/index.js 这里实现的是大数相加的方法 需要向外导出
第四步 创建webpack.config.js文件
module.exports = {
mode:'none'
entry:{
'large-number':'./src/index.js', 不需要压缩的
'large-number.min':'./src/index.js' 需要压缩的
},
output:{
filename:'[name].js',
library:'largeNumber',
libraryTarget:'umd' 各种可以导出的方法
},
optimization:{
minimize:true,
minimozer:[
new TerserPlugin({include:/\.min\.js/$}) 将带有min进行压缩
]
}
}
注意点:这里需要安装和引入 TerserPlugin
接下来我们可以在项目中的根目录定义一个index.js文件 用来区分是开发环境还是生产环境
index.js文件代码如下:
if(process.env.NODE_ENV === 'production'){
module.exports = require('./dist/large-number.min.js')
}else{
module.exports = require('./dist/large-number.js')
}
在文件中直接导入上面这个index.js文件使用便可
12 webpack实现SSR打包
服务端渲染SSR是什么? 总结就是为了减少请求。
正常的客户端渲染:HTML+CSS+JS+DATA--->渲染后的HTML
客户端渲染需要发送多个请求(HTML 数据等)
加载过程使用的是串行加载(html&数据串行加载)
服务端:所有的模板等资源都存储在服务端, 内网机器拉取数据更快 一个HTML返回所有的数据。
服务端只需要一个请求,返回HTML和数据 服务端渲染
使用步骤:服务端的代码 第一步创建服务端使用express
app.js代码如下:
if(typof window === 'undefiend') {global.window = {}}
const express = require('express')
const {renderToString} = require('react-dom/server')
const SSR = require('../dist/search-server.js') // 这里加载的是webpack打包后的压缩的js文件
server(process.env.PORT || 3000)
const server = (port)=>{
const app = express()
app.use(express.static('dist'))
app.get('/search',(req,res)=>{
res.status(200).send(renderMarkup(renderToString(SSR)))
})
app.listen(port,()=>{
console.log('Server is running on port')
})
}
const renderMarkup(str)=>{
return `<!dectype HTML>
<body>
<div id="root">${str}</div>
</body>
</HTML>`
}
第二步 客户端的代码:
创建 search-server.js
const React = require('react') //这里需要使用comjs导入
const Search extends React.Component {
render(){
return <div></div>
}
}
module.exports = <Search/>
第三步 解决样式没有显示的问题
使用打包出来的index.html模板,因为打包后的index.html会自动导入到项目中
在服务端app.js文件中将打包后的index.html进行导入
const fs = require('fs')
const path = require('path')
const data = require('./data.json') // 这是json格式的数据也是要渲染到客户端
const template = fs.readFileSync(path.join(__dirname,'../dist/index.html'),'uft-8')
然后修改renderMarkup函数:
const renderMarup = (str)=>{
const dataStr = JSON.stringify(data)
return template.replace('<!--HTML_PLACEHOLDER-->',str).replace('<!--
INITIAL_DATA_PLACEHOLDER-->',`<script>window.__initial_data=${dataStr}</script>`)
}
第四步 在模板的index.html页面中使用占位符
index.html
<body>
<div id='root'> <!--HTML_PLACEHOLDER--></div> 这里是HTML占位符
<!--INITIAL_DATA_PLACEHOLDER--> // 这里是JSON数据的占位符
</body>
13 优化构建时命令行显示的日志:统计信息stats:
webpack.config.js配置文件中
同时使用friendly-errors-webpack-plugin可以显示构建后不同的状态,成功绿色,警告黄色,报错红色
module.exports = {
plugins:[ new FriendlyErrorsWebpackPlugin() ]
stats:'errors-only' // 表示只有发生错误输出日志
}