webpack
針對 JS 的模組化打包工具
檢視當前版本 webpack --version
安裝
webpack 的執行需要依賴 node 環境,因此需要先行安裝 node 版本要大於 8.9
node 環境為了可以正常的執行很多程式碼,會包含各種依賴的包 所以安裝node 之後會自動會安裝 npm (node package manager) 用來管理 node 上面的各種包
全域性安裝 3.6.0, 因為 vue cil 2 依賴該版本: npm install webpack@3.6.0 -g
區域性安裝 : cd 到目錄 npm install webpack@3.6.0 --save--dev
為何全域性安裝後還要區域性安裝呢:
- 在終端執行 webpack 命令時,使用的都是全域性安裝的 webpack. 如 cmd 終端或者編輯器自帶的終端。
- 在 package.json 檔案中定義了 script 時,其中包含了 webpack 命令的話,那麼它優先呼叫的就是區域性的 webpack. 區域性沒有才會呼叫全域性的。 這樣在很多人一起做專案的時候只需要用區域性的打包,每個人的全域性的不一樣也不要緊。
- 一個專案往往是特定版本的 webpack, 都使用全域性的話 會導致打包出現問題
打包
src: 原始碼資料夾 (裡面有 js; hbs; cjs; sass; image; json)
dist: 打包資料夾 (distribution 釋出)(裡面有:css; js; image)
一般 src 資料夾中會由一個入口 js, main.js/index.js
這個js 會呼叫專案裡的各種其他 js. 我們會把所有的 js 打包成一個 bundle.js
cd 到資料夾,webpack 打包命令: webpack ./src/main.js ./dist/bundle.js (這裡雖然cd 到資料夾了,其實用的還是全域性 webpack)
webpack.config.js 檔案設定
- 可以把上面的"webpack 打包命令"直接簡寫成 webpack 然後在該組態檔中設定一些東西來實現 webpack ./src/main.js ./dist/bundle.js
-
const path = require('path'); //動態獲取絕對路徑需要引入的包(webpack 自帶)
module.exports = {
entry : "./src/main.js", //想要打包的主 js 檔案, 專案的入口檔案
output: {
path: path.resolve(__dirname, 'dist'), //動態的獲取絕對路徑 __dirname 是 npm 的全域性變數
filename: 'bundle.js', //打包之後生成的檔案
publicPath: 'dist/' //檔案(如圖片)打包之後傳送到的資料夾
},
module: {
rules: [
//設定 各種 loader
]
}
}
- 執行的時候 直接 cd 到資料夾 執行命令 webpack 即可呼叫區域性 webpack 進行打包工作
package.json 設定
- 它是 npm init 初始化生成的檔案
-
{
"name": "tracytestvue", //專案名稱
"version": "1.0.0", //專案版本
"description": "Tracy test vue project", //專案描述
"main": "webpack.config.js", //以後講
"dependencies": { //專案開發時依賴 這裡不需要我們自己編輯 npm insert ... 之後會自動新增到這裡
"webpack": "^3.6.0" //說明專案安裝了本地 webpack
},
"devDependencies": {//專案執行時依賴
"webpack-bundle-analyzer": "^4.4.0", //分析哪個 js 檔案大,影響頁面載入速度的
},
"scripts": { //npm run ... 的對映
"build": "webpack"// npm run build 時候執行 webpack (這裡會呼叫區域性的 webpack),
"test":"node .build/copy.js" //node 可以拋開瀏覽器直接執行js 檔案,因為伺服器沒有瀏覽器, node 的使用使得 js 檔案可以成為伺服器程式碼
},
"author": "Tracy", //作者
"license": "ISC"//開源專案的時候才會用的設
}
- 這個檔案裡是不能寫註釋的,寫註釋後就不能正確執行 npm run build 了
loader 的使用
- webpack 本身的功能只能支援 js 模組化的打包。 針對於其他檔案型別的模組化打包,我們需要給 webpack 下載不同的 loader.
- loader 涉及的打包領域有: ES6 轉 ES5, TypesScript 轉換成 ES5, 將 scss/less 轉成 css, 將 jsx/vue 檔案轉成 js 檔案
- loader 的使用過程:
步驟1: 通過 npm 安裝對應的 loader
步驟2: 在 webpack.config.js 中的 module 關鍵字下面進行設定 - loader 官網 (org 結尾的網站一般都是非盈利性質的)
loader 中文翻譯 - Demo 1 : 將 css 打包進入 bundle.js 檔案中
- 不同的 loader 都需要寫在 rules 中, rules 是一個陣列。
- Demo 2 : 打包 less, scss, sass 的樣式檔案
- main.js 引入 less : import less from './css/demo.less'
- npm install --save-dev less-loader less
- webpack.config.js 設定:
{
test: /\.less$/,
use: [{ loader: "style-loader" }, { loader: "css-loader" }, { loader: "less-loader" }]
}
- less-loader的時候經常會因為版本過高報錯, 在 package.json 檔案手動更改版本為 4.1.0 之後執行 npm install
- Demo 3: 打包 image 為 Base64 字串格式 url-loader 功能類似於 file-loader,但是在檔案大小(單位 byte)低於指定的限制時,可以返回一個 DataURL。
- css 檔案中引入 image: background-image: url('../images/view.png');
- npm install --save-dev url-loader
-
{
test: /\.(png|jpg|gif|jpeg)$/, //這裡我們自己加上 jpeg
use: [
{
loader: 'url-loader',
options: {
limit: 8192 //當載入的圖片小於 limit 的 8kb 的時候會將圖片編譯成 base64 字串形式
//當圖片大於 8kb 的時候需要再下載 file-loader, 這裡就不用額外設定什麼了
name: 'images/[name].[hash:8].[ext]' //圖片大於 limit file-loader 生成的名字
}
}
]
}
- 圖片小於 8kb 打包之後css 檔案會變成類似於: background-image:url(data:image/png;base64,iVBORw0KGgoAAAAN...=)
- 當圖片大於 設定的 limit 的 8kb 後會報錯, 此時我們需要再設定 npm install --save-dev file-loader
file-loader : 將檔案傳送到輸出資料夾,並返回(相對)URL - webpacl.config 的 output 中需要設定圖片要傳送過去的資料夾 publicPath: 'dist/'
- 其他不用再額外設定了,直接 npm run build 即可
版本過高報錯, 在 package.json 檔案手動更改版本為 "file-loader": "^4.0.0" - 檔案會被改名,成為 32位元的 hash 雜湊值。傳送到 publicPath 的資料夾
但是真實開發中,我們對打包的檔案名字是有一定的要求的,此時就要在 option 新增如下選項
name: 'images/[name].[hash:8].[ext]'
- images : 檔案要打包的資料夾
- [name] : 獲取圖片原來的名字
- [hash:8]: 放置圖片名字重複,依然使用 hash, 保留 8位元
- [ext]: 使用原來檔案的拓展名
- Demo 4: ES6 轉 ES5
- npm
- npm install babel-loader babel-core babel-preset-es2015
這裡先不要按照官網的用 babel-preset-env -
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/, //排除 node_modules 和 bower_components 裡的檔案
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}
- 如果用官網的 babel-preset-env 打包報錯後,需要在 webpack.config.js 同級目錄建立檔案" .babelrc." 然後再進行具體的設定
- 你必須執行 npm install babel-plugin-transform-runtime --save-dev 來把它包含到你的專案中,也要使用 npm install babel-runtime --save-dev 把 babel-runtime 安裝為一個依賴。
- Demo 5: 打包 .vue 檔案
- npm install vue-loader vue-template-compiler --save-dev
- webpack.config.js 設定:
module: {
rules: [{
test: /\.vue$/,
use: [
{ loader: "vue-loader"}
]
}]
}
- 此時會報錯: vue-loader was used without the corresponding plugin.
因為 vue loader 版本過高, 可以改成 ^13.0.0 (這個^的意思是會安裝 13到14之間的一個合適的版本)
重新 npm install - 引入 vue 檔案想從 import App from './vue/App.vue' 變成 import App from './vue/App'
去掉字尾名: 在 webpack.config.js 檔案中的 resolve 中設定 resolve: {
extensions:['.js', '.css', '.vue'],
}
webpack 中設定 Vue
plugin 的使用
- plugin 是外掛,對現有框架的功能進行擴充套件
- 使用步驟
- 安裝: npm *** (某些外掛webpack 已經內建因此才不用安裝)
- 設定: webpack.config.js 中的 plugins :[] 中設定外掛
- Demo: 新增版權宣告
- 安裝: 它是 webpack 內建外掛所以不用再次安裝了
- 設定 const webpack = require ('webpack');
plugins :[ new webpack.BannerPlugin('最終版權歸 Tracy 所有') ]
- 打包 html
目前的 index.html 檔案還在 dist 資料夾外面,釋出的時候還不是很方便。
需要將 html 檔案打包到 dist 資料夾中釋出的時候就拽這個資料夾即可
- 這個外掛為我們做的: 自動生成一個index.html檔案(可以指定模板來生成)
並且將打包好的 js 檔案自動通過 script 標籤插入到 index.html 的 body 中 - 安裝: npm install html-webpack-plugin --save--div
- 設定: const htmlWebpackPlugin = require('html-webpack-plugin');
new htmlWebpackPlugin({template: 'index.html'}) - 這裡的 template 表示根據什麼模板來生成 html, 我們目前的 html 是和 webpack.config.js 在同一目錄,因此直接寫的 index.html 就能找到對應的檔案
另外我們需要刪除之前在 out put 之中新增的 publicPath 屬性,否則插入的js路徑會有問題 - error : Cannot read property 'make' of undefined
方法將"html-webpack-plugin"版本由 "^4.2.0"改為 "^3.2.0", - 原來 index.html body 中只寫 <div id="app"></div> 即可,引入 js 什麼的都不用寫了
- 壓縮 JS
- 安裝: npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
- 設定: const uglifyjsPlugin = request('uglifyjs-webpack-plugin');
new uglifyjsPlugin() - 此時會發現打包報錯:報錯是因為最新版的uglifyjs-webpack-plugin外掛已經不支援es6語法, 所以已經不適合用這個外掛了
搭建本地伺服器
- 可以實現瀏覽器自動重新整理我們改動之後的效果,每次改動後專案會自動打包到記憶體中
- 安裝: npm install --save-dev webpack-dev-server@2.9.1
- 在 webpack.config.js 中設定
devServer:{ contentBase:'./dist', //為哪一個資料夾提供本地 server 服務 port:埠號, //不設定的話就是8080 inline: true, //頁面實時重新整理 historyApiFallbacl: 在SPA(單頁應用)中,依賴 htmk5 的 history 模式,以後細講 } - 在 package.json 中的 "scripts" 裡設定 "dev": "webpack-dev-server --open" (這裡的open 是指執行時候直接開啟瀏覽器)
- 啟動專案的時候 npm run dev
webpack 組態檔 config.js 的分離
- 如果把所有的設定都放倒一個 webpack.config.js 檔案中,那麼在設定很多的時候,是不太合適的.
有些東西是隻在測試環境的時候才需要設定的,比如說「搭建本地伺服器」
有些東西是隻在部署環境的時候才需要設定的,比如說醜化js 和 版權管理等 - 因此我們要把組態檔至少分成三個:
- base.config.js: 測試和部署環境都會用到的設定
- dev.config.js: 測試環境設定
- prod.config.js: 部署環境設定
- 三個檔案都放倒 build 資料夾中
base.config.js 中的設定就要改了,因為資料夾換了: path: path.resolve(__dirname, '../dist'), - 安裝 npm install webpack-merge --save-dev 用於在 dev.config.js 檔案中將它自己和 base.config.js 合併,執行的時候執行一個 dev.config.js 即可
在 dev.config.js 和 prod.config.js 中分別設定 :
const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config');
module.exports = webpackMerge.merge(baseConfig, {裡面放 dev.config.js 或者 prod.config.js 裡的 code}) - 刪除 webpack.config.js
在 package.json 檔案的 "script"中加上 --config ./build/###.config.js 用於覆蓋原來預設的 webpack.config.js 檔案的操作
"build": "webpack --config ./build/prod.config.js",
"dev": "webpack-dev-server --open --config ./build/dev.config.js"