目錄
1、安裝 2、基本使用 3、創建bundle文件 4、使用配置文件
1、webpack-dev-server自動打包編譯 2、html-webpack-plugin自動添加js入口文件
1、加載CSS、less、scss 2、加載圖片 3、加載字體
1、開發環境 2、完整版 3、運行時 4、vue-router 5、vue-resource 6、vuex
網頁中常見的靜態資源:JS(.js .jsx .coffee .ts)、CSS(.css .less .sass .scss)、Images(.jpg .png .gif .bmp .svg)、字體文件Fonts(.svg .ttf .eot .woff .woff2)、模板文件(.ejs .jade .vue)。靜態資源使網頁加載速度慢,因爲要發起很多二次請求;靜態資源間存在綜複雜的依賴關係。解決辦法:合併壓縮(sprite、圖片的Base64編碼等)、解決各個包之間複雜的依賴關係。
webpack是基於Node.js開發的前端項目構建工具。本質上,webpack是一個現代JavaScript應用程序的靜態模塊打包器(module bundler)。當webpack處理應用程序時,會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序需要的每個模塊,然後將所有模塊打包成一個或多個bundle。官網:https://webpack.github.io/ https://www.webpackjs.com/。
Gulp是基於task任務的,webpack是基於整個項目進行構建的。
一、起步
1、安裝
確保已安裝Node.js最新的長期支持版本(LTS),因爲使用舊版本可能遇到各種問題,可能缺少webpack功能以及/或者缺少相關package包。
包安裝出錯時,可刪除node_modules文件夾,運行npm install重新安裝所有包。也可以npm uninstall <包名>卸載相應的包。
(1)全局安裝
運行npm i webpack -g全局安裝。
(2)本地安裝
對於大多數項目,建議本地安裝(先全局安裝,才能使用webpack命令)。使引入破壞式變更(breaking change)的依賴時,更容易分別升級項目。在項目根目錄中運行以下命令安裝到項目依賴中。
安裝到最新版本:npm install --save-dev webpack
安裝到特定版本:npm install --save-dev webpack@<version>
使用webpack 4+版本時,還需要安裝CLI:npm install --save-dev webpack-cli,提供命令行(如webpack命令)和打包功能。
2、基本使用
webpack-demo // 根目錄
|- package.json
|- webpack.config.js // 配置文件
|- /dist // 發佈的文件
|- index.html // 首頁
|- bundle.js
|- /src // 源代碼
|- /css
|- /js
|- /images
|- main.js // js入口文件
|- /node_modules
創建項目基本的目錄結構;運行npm init -y在根目錄下創建package.json(項目是中文名使用npm init),使用npm管理項目中的依賴包;運行npm install webpack webpack-cli --save-dev本地安裝webpack。
使用npm i jquery -S安裝jquery類庫。import $ from 'jquery'導入jquery類庫。
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>起步</title>
</head>
<body>
<ul>
<li>這是第1個li</li>
<li>這是第2個li</li>
<li>這是第3個li</li>
<li>這是第4個li</li>
</ul>
<script src="./bundle.js"></script>
</body>
</html>
/* main.js */
import $ from 'jquery' // 相當於node中,const $=require('jquery')
$(function(){
// 設置背景色隔行變色
$('li:odd').css('backgroundColor','pink');
$('li:even').css('backgroundColor','#ddd');
})
import或require導入包的查找規則:項目根目錄中node_modules文件夾->根據包名找對應的文件夾->package.json包配置文件->main屬性,指定了該包在被加載時的入口文件。
3、創建bundle文件
“源”代碼(/src)是用於書寫和編輯的代碼,“分發”代碼(/dist)是構建過程產生的代碼最小化和優化後的“輸出”目錄,最終將在瀏覽器中加載。
webpack能夠很好地支持import和export語句、及多種其它模塊語法。webpack會將代碼“轉譯”,以便舊版本瀏覽器可以執行。
將src/main.js“轉譯”爲dist/bundle.js:webpack .\src\main.js --output .\dist\bundle.js(入口文件路徑 輸出文件路徑);或npx webpack,將腳本作爲入口起點,然後輸出爲main.js。
4、使用配置文件
在webpack 4中,可以無須任何配置使用,然而大多數項目會需要很複雜的設置,webpack仍然要支持配置文件,這比在終端中手動輸入大量命令要高效的多,所以讓我們創建一個取代以上使用CLI選項方式的配置文件。
使用配置文件創建bundle:webpack或npx webpack --config webpack.config.js。在控制檯直接輸入webpack命令執行時,去項目根目錄查找配置文件,解析得到導出的配置對象,拿到配置對象中指定的入口和出口,進行打包構建。webpack 4有約定,爲了儘量減少配置文件的體積,默認約定了打包的入口是./src/index.js和打包的出口是./dist/main.js。
/* webpack.config.js */
const path=require('path')
module.exports={ // node語法
entry:'./src/main.js', // 項目入口文件,默認爲'./src/index.js'
output:{
filename:'bundle.js', // 輸出的路徑
path:path.resolve(__dirname,'dist') // 輸出的文件名
}
}
導入包是,省略.jsx等後綴名;配置和使用@路徑符號。
// webpack.config.js
module.exports={
resolve:{
extensions:['.js','.jsx','.json'], // 這幾個文件後綴名可省略不寫
alias:{ // 別名
'@':path.join(__dirname,'./src')
}
}
}
// index.js
import Welcome from '@/components/Welcome' // 省略了.jsx
二、開發
1、webpack-dev-server自動打包編譯
使用webpack-dev-server工具實現代碼自動打包編譯,修改和保存任意源文件,web服務器就會自動重新加載編譯後的代碼。
(1)運行npm install --save-dev webpack-dev-server將該工具安裝到項目的本地開發依賴。該工具依賴於webpack,在本地項目中必須安裝webpack。
(2)在命令行直接運行webpack-dev-server命令進行打包,報錯,因爲webpack-dev-server是本地安裝的,無法把它當作腳本命令。需要藉助於package.json文件中的指令運行webpack-dev-server命令。在scripts節點下新增"dev": "webpack-dev-server"指令,運行npm run dev。或者新增"start": "webpack-dev-server --open --port 3000 --concentBase dist --hot",運行npm start打開服務器。
(3)命令參數
方式一:修改package.json的script節點
--open 自動在瀏覽器中打開該端口地址,後面可跟瀏覽器名稱,如firefox
--port 修改運行時的端口號
--host 修改運行時的域名,如127.0.0.1
--contentBase 設置託管的根目錄,在瀏覽器中直接打開該路徑下的.html文件
--hot 啓動瀏覽器熱更新,不會重新生成bundle.js,只會生成一個.js和.json補丁保存局部更新的代碼,並實現瀏覽器的無重載異步刷新(對css等有效果,對js無效果)
方式二:修改webpack.config.js文件,新增devServer節點
/* webpack.config.js */
const path=require('path')
const webpack=require('webpack') // 啓用熱更新使用
module.exports={
devServer:{
open:true,
port:3000,
contentBase:'./dist',
hot:true
},
plugins:[
new webpack.HotModuleReplacementPlugin() // 放置熱更新的模塊對象
]
}
(4)webpack-dev-server打包生成的bundle.js文件,在項目根目錄<script src="/bundle.js"></script>。並沒有存放到實際的物理磁盤上,而是直接託管到電腦的內存中,在根目錄找不到。由於需要實時打包編譯,放在內存中速度會非常快。
2、html-webpack-plugin自動添加js入口文件
html-webpack-plugin,自動根據指定頁面在內存中生成一個新頁面之後,所有的打包好的bundle會自動添加到新頁面的body底部。不再需要指定啓動目錄和手動處理bundle.js的引用路徑。
npm install --save-dev html-webpack-plugin。
/* webpack.config.js */
const path=require('path')
const htmlWebpackPlugin=require('html-webpack-plugin')
module.exports={
plugins:[ // 配置插件的節點
new htmlWebpackPlugin({
template:path.join(__dirname,'./dist/index.html'), // 指定模板頁面
filename:'index.html', // 指定生成頁面名稱,瀏覽器默認打開index.html
title:'Output Management'
})
]
}
三、管理資源
webpack默認只能打包處理JS類型的文件,如需引入任何其它類型的文件,需通過loader 。
webpack處理第三方文件類型的過程:發現要處理的文件不是JS文件,去配置文件中查找有沒有對應的第三方loader規則;如果有,調用對應的loader處理這種文件類型,從後往前調用;處理完畢,把處理的結果交給webpack進行打包合併,輸出到bundle.js。
1、加載CSS、less、scss
爲了從JS模塊中import一個CSS文件,需要在module配置中安裝並添加style-loader和css-loader。
/* main.js */
import './css/index.css'
import './css/index.less'
import './css/index.scss'
npm install --save-dev style-loader css-loader
npm install --save-dev less less-loader less是less-loader內部依賴,不需要顯式定義
npm install --save-dev node-sass sass-loader node-sass是sass-loader內部依賴,不需要顯式定義
/* webpack.config.js */
module.exports={
module:{ // 配置所有第三方模塊的加載器
rules:[ // 所有第三方模塊的匹配規則
{test:/\.css$/,use:['style-loader','css-loader']}, // 加載.css文件,從後往前調用
{test:/\.less$/,use:['style-loader','css-loader','less-loader']}, // 加載.less文件
{test:/\.scss$/,use:['style-loader','css-loader','sass-loader']}, // 加載.scss文件
]
}
}
2、加載圖片
file-loader和url-loader可以接收並加載任何文件。
npm install --save-dev file-loader 使用file-loader,圖片不會被編碼爲base64
npm install --save-dev url-loader file-loader是url-loader內部依賴,不需要顯式定義
{test:/\.(png|svg|jpg|gif)$/,use:'file-loader'}, // 處理圖片
{test:/\.(jpg|png|gif|bmp|jpeg)$/,use:'url-loader?limit=7631&name=[hash:8]-[name].[ext]'}
limit給定的值是圖片的大小(byte),如果圖片大於等於給定的limit值,則不會被轉爲base64格式的字符串。
圖片名默認會被修改爲哈希值,防止重名衝突。name=[name].[ext]使圖片保持原名,在前面加哈希值解決重名衝突。
3、加載字體
npm install --save-dev file-loader url-loader
{test:/\.(ttf|eot|svg|woff|woff2)$/,use:'url-loader'} // 處理字體文件
四、bable處理高級js語法
webpack默認只能處理部分ES6語法,一些更高級的ES6或ES7語法,需要藉助第三方的loader處理,轉爲低級的語法後,把結果交給webpack打包到bundle.js中。
webpack 4.x | babel-loader 8.x | babel 7.x
npm install -D babel-loader @babel/core @babel/preset-env webpack
npm install -D @babel/runtime @babel/plugin-transform-runtime @babel-runtime是依賴
babel-preset-env是較新的ES語法。(使用了static關鍵字報錯,可能是因爲這只是提案,目前不支持)
babel對一些公共方法使用了非常小的輔助代碼,如_extend。默認情況下會被添加到每一個需要它的文件中,引入babel runtime作爲一個獨立模塊,來避免重複引入。禁用babel自動對每個文件的runtime注入,而是引入babel-plugin-transform-runtime使所有輔助代碼從這裏引用。
配置babel的loader規則時,必須把node_modules目錄排除。否則,babel會把node_modules中所有的第三方JS文件都打包編譯,打包速度非常慢且非常消耗CPU,且即使編譯完畢項目也無法正常運行。
/* webpack.config.js */
module.exports={
module:{
rules:[
{test:/\.js$/,use:'babel-loader',exclude:/node_modules/} // 配置babel處理ES6等高級語法
]
}
}
在項目的根目錄中,新建一個.babelrc的babel配置文件,該文件是JSON格式,不能寫註釋,字符串必須用雙引號。preset預設,可翻譯爲語法。
{
"presets":["@babel/preset-env"],
"plugins":["@babel/plugin-transform-runtime"]
}
babel默認啓用嚴格模式,如果要移除嚴格模式,npm install babel-plugin-transform-remove-strict-mode,並修改.babelrc。
{
"plugins":["transform-remove-strict-mode"]
}
五、Vue
1、開發環境
開發環境下,Vue會提供很多警告來對付常見的錯誤與陷阱。當使用webpack構建工具時,Vue源碼會根據process.env.NODE_ENV決定是否啓用開發環境模式。
/* webpack.config.js */
// webpack 4+
module.exports={
mode:'development'
}
// webpack 3及其更低版本
var webpack=require('webpack')
module.exports={
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV':JSON.stringify('production')
})
]
}
2、完整版
npm install --save-dev vue
使用import Vue from 'vue'導入Vue構造函數時,"main": "dist/vue.runtime.common.js",只提供了runtime-only的方式。如果需要在客戶端編譯模板(如傳入一個字符串給template選項,或掛載到一個元素上並以其DOM內部的HTML作爲模板),就需要加上編譯器,即完整版。否則會報錯[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
方式1:
/* main.js */
import Vue from '../node_modules/vue/dist/vue.js'
方式2:每次需要重新啓動服務器
/* main.js */
import Vue from 'vue'
/* webpack.config.js */
module.exports={
resolve:{
alias:{
"vue$":"vue/dist/vue.esm.js" // 設置Vue被導入包時的路徑
}
}
}
3、運行時
運行時版本相比完整版體積要小大約30%,所以應該儘可能使用這個版本。
npm install --save-dev vue
npm install --save-dev vue-loader vue-template-compiler vue-template-compiler是依賴
/* main.js */
import Vue from 'vue'
import login from './login.vue' // 導入login組件
new Vue({
el:'#app',
render:function(createElement){
return createElement(login)
}
// 簡寫爲render:c=>c(login)
})
/* webpack.config.js */
const VueLoaderPlugin=require('vue-loader/lib/plugin')
module.exports={
module:{
rules:[
{test:/\.vue$/,use:'vue-loader'} // 配置.vue文件
]
},
plugins:[
new VueLoaderPlugin()
]
}
4、vue-router
npm install --save-dev vue
npm install --save-dev vue-router
如果在一個模塊化工程中使用它,必須通過Vue.use()明確地安裝路由功能。
/* main.js */
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import app from './app.vue'
import router from './router.js'
new Vue({
el:'#app',
render:c=>c(app),
router
})
將<router-link>和<router-view>放到render渲染的<template>中。
/* app.vue */
<template>
<div>
<p>render渲染的組件</p>
<router-link to="/foo">To Foo</router-link>
<router-link to="/bar">To Foo</router-link>
<router-view></router-view>
</div>
</template>
將定義、註冊路由抽離爲router.js
/* router.js */
import VueRouter from 'vue-router'
import foo from './main/Foo.vue'
import bar from './main/Bar.vue'
var router=new VueRouter({
routes:[
{path:'/foo',component:foo},
{path:'/bar',component:bar}
]
})
export default router // 向外暴露router對象
5、vue-resource
npm install --save-dev vue
npm install --save-dev vue-resource
/* main.js */
import Vue from 'vue'
import VueResource from 'vue-resource'
Vue.use(VueResource)
6、vuex
npm install --save-dev vue
npm install vuex --save
npm install es6-promise --save Vuex依賴Promise,如果瀏覽器並沒有實現Promise(如IE)
/* main.js */
import Vue from 'vue'
// import 'es6-promise/auto'
import Vuex from 'vuex'
Vue.use(Vuex)