官網指南地址javascript
webpack
最出色的功能之一就是,除了JavaScript
,還能夠經過loader
引入任何其餘類型的文件。webpack.config.js
配置以下:css
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
},
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader'
]
},
{
test: /\.xml$/,
use: [
'xml-loader'
]
}
]
}
};
複製代碼
配置
HtmlWebpackPlugin
插件自動生成index.html
;配置CleanWebpackPlugin
插件自動清理dist
目錄;WebpackManifestPlugin
插件能夠提取manifest
。webpack.config.js
配置以下:html
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Output Management'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
複製代碼
development
)和生產環境(production
)的構建目標差別很大。live reloading
)或熱模塊替換(hot module replacement
)能力的 source map
和 localhost server
。bundle
,更輕量的 source map
,以及更優化的資源,以改善加載時間。webpack
配置。webpack-merge
的工具合併配置npm install --save-dev webpack-merge
複製代碼
UglifyJSPlugin
或其餘工具source map
用仍是不用?library
將經過與 process.env.NODE_ENV
環境變量關聯,以決定 library
中應該引用哪些內容new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
複製代碼
ExtractTextPlugin
:將 CSS
分離成單獨的文件CLI
替代選項:原來用的一些插件如今能夠替換成一些優化配置項:例如,--optimize-minimize
標記將在後臺引用 UglifyJSPlugin
。和以上描述的 DefinePlugin
實例相同,--define process.env.NODE_ENV="'production'"
也會作一樣的事情。而且,webpack -p
將自動地調用上述這些標記,從而調用須要引入的插件。webpack/node/npm
loader/plugins
;必要的話也用在儘可能最少數的必要模塊中;能夠將很是消耗資源的 loaders 轉存到 worker pool
中//使用 include 字段僅將 loader 模塊應用在實際須要用其轉換的位置中:
{
test: /\.js$/,
include: path.resolve(__dirname, "src"),
loader: "babel-loader"
}
複製代碼
Dlls
:使用 DllPlugin
將更改不頻繁的代碼進行單獨編譯。這將改善引用程序的編譯速度,即便它增長了構建過程的複雜性。Smaller = Faster
:減小編譯的總體大小,以提升構建性能。儘可能保持 chunks
小巧。cache-loader
啓用持久化緩存。使用 package.json
中的 postinstall
清除緩存目錄。thread-loader
能夠將很是消耗資源的 loaders
轉存到 worker pool
中resolve.modules, resolve.extensions, resolve.mainFiles, resolve.descriptionFiles
中類目的數量,由於他們會增長文件系統調用的次數。symlinks
,能夠設置 resolve.symlinks: false
。plugins
,而且沒有指定 context
信息,能夠設置 resolve.cacheWithContext: false
。UglifyJsPlugin、ExtractTextPlugin、[hash]/[chunkhash]、AggressiveSplittingPlugin、AggressiveMergingPlugin、ModuleConcatenationPlugin
devtool
的設置,會致使不一樣的性能差別webpack-dev-server
chunk
的體積,以提升性能tree shaking
tree shaking
是一個術語,一般用於描述移除JavaScript
上下文中的未引用代碼(dead-code
)。新的webpack 4
正式版本,擴展了這個檢測能力,經過package.json
的sideEffects
屬性做爲標記,向compiler
提供提示,代表項目中的哪些文件是pure
(純的ES2015
模塊)",由此能夠安全地刪除文件中未使用的部分。vue
sideEffects
:將文件標記爲無反作用 如同上面提到的,若是全部代碼都不包含反作用,咱們就能夠簡單地將該屬性標記爲 false,來告知 webpack,它能夠安全地刪除未用到的 export 導出。{
"name": "your-project",
"sideEffects": false
}
複製代碼
若是你的代碼確實有一些反作用,那麼能夠改成提供一個數組:java
{
"name": "your-project",
"sideEffects": [
"./src/some-side-effectful-file.js"
]
}
複製代碼
bundle
中刪除它們。爲此,咱們將使用 -p(production)
這個 webpack
編譯標記,來啓用 uglifyjs
壓縮插件。
--optimize-minimize
標記也會在 webpack
內部調用 UglifyJsPlugin
。)webpack 4
開始,也能夠經過 mode
配置選項輕鬆切換到壓縮輸出,只需設置爲 production
。
在
vue
單頁應用中,當項目不斷完善豐富時,即便使用webpack
打包,文件依然是很是大的,影響頁面的加載。若是咱們能把不一樣路由對應的組件分割成不一樣的代碼塊,當路由被訪問時才加載對應的組件(也就是按需加載),這樣就更加高效了。——引自vue-router
官方文檔node
非動態加載時的打包狀況以下圖: jquery
hello
組件的加載方式
改成路由懶加載[import()語法],在進行打包
// import Hello from '@/components/Hello'
export default new Router({
routes: [
{
path: '/',
name: 'Hello',
// component: Hello,
component: () => import('@/components/Hello')
}
]
})
複製代碼
4個js
文件,仔細的同窗還發現,app.js
文件的大小加上新多出文件的大小,約等於沒有分割打包的app
的大小。js
,在頁面首次加載的時候不須要加載他,等到請求相應的頁面的時候在去服務器請求它,減少了頁面首屏加載的時間。webpack.prod.conf.js
中配置 output.chunkFilename
規定了打包異步文件的格式//webpack.prod.conf.js:生產打包js
//utils.assetsPath是utils.js中封裝的一個路徑相關的方法
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
/** 本人在本身的工程中刪除或修改chunkFilename的配置, 最後仍是都按這個規則生產js文件了, Why? */
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
複製代碼
lodash.bundle.js
,在技術概念上「懶加載」它。問題是加載這個包並不須要用戶的交互 -- 意思是每次加載頁面的時候都會請求它。這樣作並無對咱們有不少幫助,還會對性能產生負面影響。//src/index.js
- import _ from 'lodash';
-
- function component() {
+ function getComponent() {
- var element = document.createElement('div');
-
- // Lodash, now imported by this script
- element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+ return import(/* webpackChunkName: "lodash" */ 'lodash').then(_ => {
+ var element = document.createElement('div');
+
+ element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+
+ return element;
+
+ }).catch(error => 'An error occurred while loading the component');
}
- document.body.appendChild(component());
+ getComponent().then(component => {
+ document.body.appendChild(component);
+ })
複製代碼
客戶端(一般是瀏覽器)獲取資源是比較耗費時間的。能夠經過命中緩存,以下降網絡流量,使網站加載速度更快;然而,緩存的存在可能會使你獲取新代碼時比較棘手(文件名不變的話)。如何經過必要的配置,以確保
webpack
編譯生成的文件可以被客戶端緩存,而在文件內容變化後,可以請求到新的文件。webpack
output.filename
進行文件名替換
webpack
在入口 chunk
中,包含了某些樣板(boilerplate
),特別是 runtime
和 manifest
。(譯註:樣板(boilerplate
)指 webpack
運行時的引導代碼)webpack
生成的 hash
發生改變,manifest
文件也會發生改變。所以,vendor bundle
的內容也會發生改變,而且失效。因此,咱們須要將 manifest
文件提取出來。CommonsChunkPlugin
將manifest
提取出來
webpack
裏每一個模塊都有一個 module id
,module id
是該模塊在模塊依賴關係圖裏按順序分配的序號,若是這個 module id
發生了變化,那麼他的 chunkhash
也會發生變化。module id
總體發生改變,可能會致使全部文件的chunkhash
發生變化,這顯然不是咱們想要的HashedModuleIdsPlugin
,根據模塊的相對路徑生成一個四位數的hash做爲模塊id,這樣就算引入了新的模塊,也不會影響 module id
的值,只要模塊的路徑不改變的話。new webpack.HashedModuleIdsPlugin()
複製代碼
library
除了打包應用程序代碼,
webpack
還能夠用於打包JavaScript library
;即咱們平時npm install
下來的那種依賴包git
個人demo:element-ui表單的二次封裝github
最後,
package.json
中配置"main": "dist/ginna-form.js"
;咱們從node_modules
引入時就靠這個屬性來找到對應的文件的哦。
shimming
webpack
編譯器(compiler
)可以識別遵循ES2015
模塊語法、CommonJS
或AMD
規範編寫的模塊。然而,一些第三方的庫(library
)可能會引用一些全局依賴(例如jQuery
中的$
)。這些庫也可能建立一些須要被導出的全局變量。 這些「不符合規範的模塊」就是shimming
發揮做用的地方
shim
:一種庫(library
)的抽象,這種庫能將一個新的API
引入到一箇舊的環境中,並且僅靠舊的環境中已有的手段實現。polyfill
就是一個用在瀏覽器API
上的shim
。
jQuery
做爲全局變量,能夠被別的組件引用this
置爲window
當模塊運行在 CommonJS
環境下this
會變成一個問題,也就是說此時的 this
指向的是 module.exports
。在這個例子中,你能夠經過使用 imports-loader
覆寫 this
:
library
),和下面所展現的代碼相似。exports-loader
,將一個全局變量做爲一個普通的模塊來導出。例如,爲了將 file
導出爲 file
以及將 helpers.parse
導出爲 parse
babel-polyfill
按需加載Babel
是一個普遍使用的轉碼器,能夠將ES6
代碼轉爲ES5
代碼,從而能夠在現有環境執行,因此咱們能夠用ES6
編寫,而不用考慮環境支持的問題。Babel
默認只轉換新的JavaScript
語法(syntax
),如箭頭函數等,而不轉換新的API
,好比Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise
等全局對象,以及一些定義在全局對象上的方法(好比Object.assign
)都不會轉碼;所以咱們須要polyfill
;
babel-preset-env
babel-preset-env
是一個新的preset
,能夠根據配置的目標運行環境(environment
)自動啓用須要的 babel
插件javascript
代碼時,須要使用 N
個 preset
,好比:babel-preset-es201五、babel-preset-es2016
。es2015
能夠把 ES6
代碼編譯爲 ES5
,es2016
能夠把 ES2016
代碼編譯爲 ES6
。babel-preset-latest
能夠編譯 stage 4
進度的 ECMAScript
代碼。preset
,包括沒必要要的。babel-preset-env
的工做方式相似 babel-preset-latest
,惟一不一樣的就是它會根據配置的 env
只編譯那些還不支持的特性。es20xx presets
了。script-loader
會在全局上下文中對代碼進行取值,相似於經過一個 script
標籤引入腳本。在這種模式下,每個標準的庫(library
)都應該能正常運行AMD/CommonJS
規範版本,但你也想將他們加入 dist
文件,你可使用 noParse
來標識出這個模塊noParse:這是module中的一個屬性,
做用:不去解析屬性值表明的庫的依賴
舉例:
咱們通常引用jquery,能夠以下引用:
import jq from 'jquery'
對於上面的解析規則:
當解析jq的時候,會去解析jq這個庫是否有依賴其餘的包
咱們對相似jq這類依賴庫,通常會認爲不會引用其餘的包(特殊除外,自行判斷)。
因此,對於這類不引用其餘的包的庫,咱們在打包的時候就沒有必要去解析,
這樣可以增長打包速率。
因此,能夠在webpack的配置中增長noParse屬性
(如下代碼只須要看module的noParse屬性)
module.exports = {
mode:'development',
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'dist')
},
module:{
noParse:/jquery/,//不去解析jquery中的依賴庫
rules:[ ]
}
}
複製代碼
PWA
漸進式網絡應用程序(
Progressive Web Application - PWA
),是一種能夠提供相似於原生應用程序(native app
)體驗的網絡應用程序(web app
)。PWA
能夠用來作不少事。其中最重要的是,在離線(offline
)時應用程序可以繼續運行功能。這是經過使用名爲Service Workers
的網絡技術來實現的。
//print.js
export default function printMe() {
console.log('I get called from print.js!');
}
//index.js
import printMe from './print.js';
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('./service-worker.js').then(registration => {
console.log('SW registered: ', registration);
}).catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
});
}
function component() {
var element = document.createElement('div');
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
var btn = document.createElement('button');
btn.innerHTML = 'Click me and check the console!';
btn.onclick = printMe;
element.appendChild(btn);
return element;
}
document.body.appendChild(component());
//webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const WorkboxPlugin = require('workbox-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
//3個插件都須要npm install --save-dev
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Output Management'
title: 'Progressive Web Application'
}),
//添加 Workbox
new WorkboxPlugin.GenerateSW({
// 這些選項幫助 ServiceWorkers 快速啓用
// 不容許遺留任何「舊的」 ServiceWorkers
clientsClaim: true,
skipWaiting: true
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
//package.json配置腳本
"scripts": {
"build": "webpack",
//使用一個簡易服務器,搭建出咱們所需的離線體驗
//npm install http-server --save-dev
"start": "http-server dist"
},
複製代碼
Workbox
,咱們再看下執行 npm run build
時會發生什麼clean-webpack-plugin: /mnt/c/Source/webpack-follow-along/dist has been removed.
Hash: 6588e31715d9be04be25
Version: webpack 3.10.0
Time: 782ms
Asset Size Chunks Chunk Names
app.bundle.js 545 kB 0, 1 [emitted] [big] app
print.bundle.js 2.74 kB 1 [emitted] print
index.html 254 bytes [emitted]
precache-manifest.b5ca1c555e832d6fbf9462efd29d27eb.js 268 bytes [emitted]
service-worker.js 1 kB [emitted]
[0] ./src/print.js 87 bytes {0} {1} [built]
[1] ./src/index.js 477 bytes {0} [built]
[3] (webpack)/buildin/global.js 509 bytes {0} [built]
[4] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 1 hidden module
Child html-webpack-plugin for "index.html":
1 asset
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 2 hidden modules
複製代碼
service-worker.js
(或sw.js
) 和體積很大的 precache-manifest.b5ca1c555e832d6fbf9462efd29d27eb.js
。sw.js
是 Service Worker
文件,precache-manifest.b5ca1c555e832d6fbf9462efd29d27eb.js
是 sw.js
引用的文件,因此它也能夠運行npm start
啓動服務。訪問 http://localhost:8080/index.html
並查看 console
控制檯。在那裏你應該看到:SW registered
複製代碼
Service Worker
,你應該能夠看到你的應用程序還在正常運行。然而,服務器已經中止了服務,此刻是 Service Worker
在提供服務。TypeScript
準備工做:
ts-loader
插件、tsconfig.json
配置文件(和package.json
同級)、ts
文件中如何使用第三方庫(ts
聲明文件*.d.ts
)
webpack.config.js
配置
tsconfig.json
案例:
npm
安裝第三方庫時,必定要牢記同時安裝這個庫的類型聲明文件。你能夠從 TypeSearch
中找到並安裝這些第三方庫的類型聲明文件。舉個例子,若是想安裝 lodash
這個庫的類型聲明文件,咱們能夠運行下面的命令:npm install --save-dev @types/lodash
TypeScript
學習