前言:在看本文前,建议你看下,下面这两篇文章 顺便给个赞和
github
的赞哦~javascript
若是你对webpack
不是很了解,请你关注我以前的文章,都是百星以上star
的高质量文css
文章内容都会不按期更新 记得必定要收藏
webpack
用了会上瘾,它也是突破你技术瓶颈的好方向,如今基本上任何东西都离不开webpack
,webpack
用得好,什么next nuxt
随便上手(本人体会很深),本人参考了Vue
脚手架,京东的webpack
优化方案,以及本人的其余方面优化,着重在生产模式
下的构建速度优化提高很是明显(固然开发环境下也是~),性能提高很明显哦~.Vue
文件和template模板
tree shaking
摇树优化 删除掉无用代码async / await
和 箭头函数PWA
功能,热刷新,安装后当即接管浏览器 离线后仍让能够访问网站 还能够在手机上添加网站到桌面使用preload
预加载资源prefetch
按需请求资源CSS
模块化,不怕命名冲突base64
处理sx js json
等VueRouter
路由懒加载,按需加载 , 代码分割 指定多个路由同个chunkName
而且打包到同个chunk
中 实现代码精确分割less sass stylus
等预处理code spliting
优化首屏加载时间 不让一个文件体积过大chunkhash
,每一个文件有对应的contenthash
,方便浏览器区别缓存CSS
压缩CSS
前缀 兼容各类浏览器code spliting
CSS
文件单独抽取出来每隔三天,技术就会进步一次
正式开始吧,假设你已经懂什么是
entry output loader plugin
,若是不懂,看我上面的文章哦~html
// 入口文件
entry: {
app: './src/js/index.js',
},
// 输出文件
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/' //确保文件资源可以在 http://localhost:3000 下正确访问
},
// 开发者工具 source-map
devtool: 'inline-source-map',
// 建立开发者服务器
devServer: {
contentBase: './dist',
hot: true // 热更新
},
plugins: [
// 删除dist目录
new CleanWebpackPlugin(['dist']),
// 从新穿件html文件
new HtmlWebpackPlugin({
title: 'Output Management'
}),
// 以便更容易查看要修补(patch)的依赖
new webpack.NamedModulesPlugin(),
// 热更新模块
new webpack.HotModuleReplacementPlugin()
],
// 环境
mode: "development",
// loader配置
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
}
复制代码
这里面咱们重点关注
module
和plugins
属性,由于今天的重点是编写loader
和plugin
,须要配置这两个属性。vue
webpack
启动后,在读取配置的过程当中会先执行 new MyPlugin(options)
初始化一个MyPlugin
得到其实例。在初始化 compiler
对象后,再调用 myPlugin.apply(compiler)
给插件实例传入 compiler
对象。 插件实例在获取到 compiler
对象后,就能够经过 compiler.plugin
(事件名称, 回调函数) 监听到 Webpack
广播出来的事件。 而且能够经过 compiler 对象去操做 webpack。java
Compiler
对象包含了 Webpack
环境全部的的配置信息,包含options,loaders,plugins
这些信息,这个对象在Webpack
启动时候被实例化,它是全局惟一的,能够简单地把它理解为Webpack
实例;webpack
Compilation
对象包含了当前的模块资源、编译生成资源、变化的文件等。当 Webpack 以开发模式运行时,每当检测到一个文件变化,一次新的
Compilation 将被建立。
Compilation 对象也提供了不少事件回调供插件作扩展。经过
Compilation 也能读取到
Compiler` 对象。git
Compiler 和 Compilation
的区别在于:es6
Compiler
表明了整个Webpack
从启动到关闭的生命周期,而 Compilation
只是表明了一次新的编译。github
事件流web
webpack
经过 Tapable
来组织这条复杂的生产线。
webpack
的事件流机制保证了插件的有序性,使得整个系统扩展性很好。
webpack
的事件流机制应用了观察者模式,和 Node.js 中的 EventEmitter
很是类似。
识别入口文件
经过逐层识别模块依赖。(Commonjs、amd
或者es6
的import,webpack
都会对其进行分析。来获取代码的依赖)
webpack
作的就是分析代码。转换代码,编译代码,输出代码
最终造成打包后的代码
这些都是webpack
的一些基础知识,对于理解webpack的工做机制颇有帮助。
commonjs
模块化方案,若是你不是很懂,那么看起来很费劲,我写的脚手架,就不使用模块化方案了,简单粗
暴开始开发环境配置
包管理器 使用yarn
不解释 就用yarn
配置webpack.dev.js
开发模式下的配置
yarn init -y
yarn add webpack webpack-cli
(yarn
会自动添加依赖是线上依赖仍是开发环境的依赖)
entry: path.resolve(__dirname, '../src/main.js')}
复制代码
output: {
filename: 'js/[name].[hash:5].js',
path: path.resolve(__dirname, '../dist'),
},
复制代码
Vue
脚手架里基本配置的loader
,后面的loader
都是往rules
数组里加就好了~module: {
rules: [
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 10000,
name: 'img/[name]-[hash:5].[ext]',
}
}
]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'fonts/[name]-[hash:5].[ext]',
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 4096,
name: 'media/[name]-[hash:5].[ext]',
}
}
]
}
]
},
复制代码
有人会问 这么多我怎么看啊 别急 第一个
url-loader
是处理base64
图片的,让低于limit
大小的文件以base64
形式使用,后面两个同样的套路,只是换了文件类型而已 ,不会的话,先复制过去跑一把?
.vue
文件和tempalte
模板 , yarn add vue vue-loader vue-template-compiler
加入loader
{
test:/\.vue$/,
loader:"vue-loader"
}
加入plugin
const vueplugin = require('vue-loader/lib/plugin')
在webpack的plugin中
new vueplugin()便可
复制代码
babel-polifill
,vendor
代码分割公共模块,打包后这些代码都会在一个公共模块app: ['babel-polyfill', './src/index.js', './src/pages/home/index.js', './src/pages/home/categorys/index.jsx'],
vendor: ['vuex', 'better-scroll', 'mint-ui', 'element-ui']
```
#### 指定 `html`文件为模板打包输出,自动引入打包后的`js`文件
复制代码
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname,'../index.html'), filename: 'index.html' }), ]
#### 省掉`.vue`的后缀 ,直接配置在`module.exports`对象中,跟`entry`同级
复制代码
resolve: { extensions: ['.js','.json','.vue'],
}
复制代码
#### 加入识别`html`文件的`loader`
复制代码
{
test: /\.(html)$/,
loader: 'html-loader'
}
```
复制代码
const os = require('os')
{
loader: 'thread-loader',
options: {
workers: os.cpus().length
}
}
复制代码
babel-loader
加入 babel-loader 还有 解析JSX ES6语法的 babel preset@babel/preset-env解析es6语法
@babel/plugin-syntax-dynamic-import解析vue的 import按需加载,附带code spliting功能
{
test: /\.(js|jsx)$/,
use:
{
loader: 'babel-loader',
options: {
presets: ["@babel/preset-env", { "modules": false }] ,//附带`tree shaking`
plugins: ["@babel/plugin-syntax-dynamic-import"]
},
cacheDirectory: true//开启babel编译缓存
}
},
复制代码
babel
配置后 咱们躺着就能够用vueRouter
的路由懒加载了当打包构建应用时,JavaScript 包会变得很是大,影响页面加载。若是咱们能把不一样路由对应的组件分割成不一样的代码块,而后当路由被访问的时候才加载对应组件,这样就更加高效了。
结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载。
首先,能够将异步组件定义为返回一个 Promise 的工厂函数 (该函数返回的 Promise 应该 resolve 组件自己):
const Foo = () => Promise.resolve({ /* 组件定义对象 */ })
第二,在 Webpack 中,咱们可使用动态 import语法来定义代码分块点 (split point):
import('./Foo.vue') // 返回 Promise
注意
若是您使用的是 Babel,你将须要添加 syntax-dynamic-import 插件,才能使 Babel 能够正确地解析语法。
结合这二者,这就是如何定义一个可以被 Webpack 自动代码分割的异步组件。
const Foo = () => import('./Foo.vue')
在路由配置中什么都不须要改变,只须要像往常同样使用 Foo:
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
# 把组件按组分块
有时候咱们想把某个路由下的全部组件都打包在同个异步块 (chunk) 中。只须要使用 命名 chunk,一个特殊的注释语法来提供 chunk name (须要 Webpack > 2.4)。
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
Webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中。
复制代码
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new webpack.HotModuleReplacementPlugin(),
devServer: {
contentBase: '../build',
open: true,
port: 5000,
hot: true
},
复制代码
less-css
识别的模块{
test: /\.(less|css)$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader'
, options: {
modules: false, //不建议开启css模块化,某些ui组件库可能会按需加载失败
localIdentName: '[local]--[hash:base64:5]'
}
},
{
loader: 'less-loader',
options: { javascriptEnabled: true }
}
]
},
```
>下面正式开始生产环境
### 踩坑是好事 为何此次不放完整的源码 由于不去踩坑 永远提高不了技术
#### `html`杀掉无效的代码
复制代码
new HtmlWebpackPlugin({ template: './src/index.html', minify: { removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true, useShortDoctype: true, removeEmptyAttributes: true, removeStyleLinkTypeAttributes: true, keepClosingSlash: true, minifyJS: true, minifyCSS: true, minifyURLs: true, } }),
#### 加入图片压缩 性能优化很大
复制代码
{ test: /.(jpg|jpeg|bmp|svg|png|webp|gif)$/,
use:[
{loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[name].[hash:8].[ext]',
outputPath:'/img'
}},
{
loader: 'img-loader',
options: {
plugins: [
require('imagemin-gifsicle')({
interlaced: false
}),
require('imagemin-mozjpeg')({
progressive: true,
arithmetic: false
}),
require('imagemin-pngquant')({
floyd: 0.5,
speed: 2
}),
require('imagemin-svgo')({
plugins: [
{ removeTitle: true },
{ convertPathData: false }
]
})
]
}
}
]
}
```
复制代码
{
exclude: /\.(js|json|less|css|jsx)$/,
loader: 'file-loader',
options: {
outputPath: 'media/',
name: '[name].[contenthash:8].[ext]'
}
}
复制代码
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
new OptimizeCssAssetsWebpackPlugin({
cssProcessPluginOptions:{
preset:['default',{discardComments: {removeAll:true} }]
}
}),
复制代码
vue
脚手架是同步异步分开割,我是直接一块儿割optimization: {
runtimeChunk:true, //设置为 true, 一个chunk打包后就是一个文件,一个chunk对应`一些js css 图片`等
splitChunks: {
chunks: 'all' // 默认 entry 的 chunk 不会被拆分, 配置成 all, 就能够了拆分了,一个入口`JS`,
//打包后就生成一个单独的文件
}
}
复制代码
pwa这个技术其实要想真正用好,仍是须要下点功夫,它有它的生命周期,以及它在浏览器中热更新带来的反作用等,须要认真研究。能够参考百度的lavas框架发展历史~
const WorkboxPlugin = require('workbox-webpack-plugin')
new WorkboxPlugin.GenerateSW({
clientsClaim: true, //让浏览器当即servece worker被接管
skipWaiting: true, // 更新sw文件后,当即插队到最前面
importWorkboxFrom: 'local',
include: [/\.js$/, /\.css$/, /\.html$/,/\.jpg/,/\.jpeg/,/\.svg/,/\.webp/,/\.png/],
}),
```
#### 单页面应用的优化核心 :
* 最重要的是路由懒加载 代码分割
* 部分渲染在服务端完成 极大加快首屏渲染速度 `VUE`首选`nuxt`框架,也可使用它的脚手架
* 图片压缩和图片懒加载是对页面层次最大的优化之一
* 后面继续书写`next nuxt`和`pwa`的使用~
> 脚手架的搭建过程不少坑,可是却能大大提高你的技术天花板,跟着做者一块儿踩坑吧,别忘了来个人`github`点赞哦~ [仓库源码地址~欢迎star][4]
[1]: /img/bVbsKJj
[2]: https://segmentfault.com/a/1190000019126657
[3]: https://segmentfault.com/a/1190000018827395
[4]: https://github.com/JinJieTan/React-webpack复制代码