前言:在看本文前,建議你看下,下面這兩篇文章 順便給個贊和
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複製代碼