在開始以前,咱們先來看如下Webpack官網首頁的圖片,思考已下該圖片表達的意義css
思考:在網頁中,咱們常常會引入哪些常見的靜態資源html
- JS
- .js .jsx .coffee .ts(TypeScript 類 C# 語言)
- CSS
- .css .less .sass .scss
- Images
- .jpg .png .gif .bmp .svg
- 字體文件(Fonts)
- .svg .ttf .eot .woff .woff2
- 模板文件
- .ejs .jade .vue【這是在webpack中定義組件的方式,推薦這麼用】
問題:網頁中靜態資源多了之後存在的問題前端
- 網頁加載速度變慢,由於要屢次重複的發送資源請求
- 要處理錯綜複雜的依賴關係
如何解決上述兩個問題?vue
- 合併、壓縮、精靈圖、圖片的Base64編碼
- 可使用以前學過的requireJS、也可使用webpack能夠解決各個包之間的複雜依賴關係;
Webpack是一個前端的項目構建工具,它是基於node.js開發出來的一個前端工具node
如何實現上述的2種解決方案?jquery
- 使用Gulp, 是基於 task 任務的;
- 使用Webpack, 是基於整個項目進行構建的;
- 藉助於webpack這個前端自動化構建工具,能夠完美實現資源的合併、打包、壓縮、混淆等諸多功能。
- 根據官網的圖片介紹webpack打包的過程
- webpack官網
Webpack支持如下規範webpack
//moduleA.js 導出
module.exports = function(){
//...
}
//moduleB.js 導入
var moduleA = require('./moduleA')
複製代碼
//moduleA.js 導入和導出
define(['jquery','./math.js'],function($,math){
//AMD是依賴前置,將文件的依賴經過數組的形式導入,而後看成函數的參數傳遞進函數使用
//經過return來實現對外接口
return helloWorld
})
複製代碼
CMD規範(推崇就近依賴,須要用到的時候再去加載模塊)git
標準語法:define(id?,deps?,factory)github
- 一個文件一個模塊,因此常常用文件名做爲模塊id
- CMD推崇依賴就近,因此通常不在define的參數中寫依賴,在factory中寫
- factory是一個函數,該函數擁有三個參數 function(require,exports,module)
- require:一個方法,接收模塊標識,用來獲取其它模塊提供的接口
- exports:一個對象,用來向外提供模塊接口
- module:一個對象,存儲了與當前模塊相關聯的一些屬性和方法
define(fcuntion(require,exports,module){
var $ = require('jquery.js')
})
複製代碼
//moduleA.js 導出
//...內容區
//導出函數(還能夠導出對象以及任何你想導出的數據類型)
exports.func = someFunc
//moduleB.js 導入
import func from './moduleA'
複製代碼
npm i webpack -g
全局安裝Webpack,這樣就能在全局使用Webpack命令
webpack4.0
以上的版本,須要全局安裝 Webpack-cli
npm i webpack --save-dev
安裝到項目依賴中npm info webpack
複製代碼
npm install webpack@版本號
複製代碼
npm uninstall webpack webpack-cli -g
複製代碼
目標:使用Webpack打包構建列表隔行變色案例
建立基本的目錄結構
webpack-study
在項目目錄下面運行npm init
初始化項目
使用 npm i jquery --save
安裝jquery類庫
建立main.js並書寫各行變色的代碼邏輯
main.js
//導入jquery內庫
import $ from 'jquery'
$(function(){
$("li:odd").css('backgroundColor','red')
$("li:even").css('backgroundColor','tomato')
})
複製代碼
在頁面直接引用main.js會報錯,由於瀏覽器不認識ES6的新語法import,須要使用Webpack進行處理,Webpack默認會把這種高級語法轉換爲低級瀏覽器可以識別的語法
運行 webpack 入口文件路徑 輸出文件路徑
對main.js進行處理
webpack ./src/main.js ./dist/bundle.js
複製代碼
在index.html中引入bundle.js代替main.js
問題描述:
webpack 入口文件路徑 輸出文件路徑
來對文件進行處理,使用起來比較繁瑣期待實現:
實現方法
const path = require('path')
module.exports = {
entry:path.join(__dirname,'./src/main.js'),
output:{
path:path.join(__dirname,'./dist'),
filename:'bundle.js'
}
}
複製代碼
問題描述:每次改完代碼,都須要手動執行webpack
命令打包編譯文件,比較繁瑣
目標:每次改完代碼,咱們點擊保存以後就能夠幫咱們自動打包編譯
安裝 webpack-dev-server
npm install webpack-dev-server -D
複製代碼
在 package.json
裏面的 scripts
屬性裏面添加 webpack-dev-server
命令到開發環境
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server"
},
複製代碼
在本地安裝webpack,webpack-dev-server想要在本地項目中運行,必須在項目中也安裝 webpack
npm install webpack -D
複製代碼
執行 npm run dev
命令便可,會有以下返回
由第四步可知,webpack-dev-server幫咱們生成的bundle.js運行於項目根目錄,這個文件並無存到物理磁盤上,而是託管到了電腦內存中,因此咱們在項目中根本看不到這個bundle.js文件,可是咱們能夠經過將index.html中的bundle.js引用路徑修改成項目根路徑,便可引用到該文件
<script src="/bundle.js"></script>
複製代碼
能夠認爲 webpack-dev-server
把打包好的文件,以一種虛擬的形式,託管到了項目的根目錄中,雖然咱們看不到它,可是能夠認爲和 dist,src,nodemodule
,平級,有一個看不見的文件,叫作bundle.js
注意:
webpack-dev-server
除了幫咱們實現自動編譯打包的功能以外,還能夠添加 額外的參數幫咱們實現更強大的功能
--open
--port 3000
--contentBase src
--hot
//package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --open --port 3000 --contentBase src --hot"
},
複製代碼
//webpack.config.js
const webpack = require('webpack') //引入Webpack,啓用熱更新的第2步
devServer:{ //設置dev-server命令參數的第二種形式,相對麻煩一些
open:true,
port:3000,
contentBase:'src',
hot:true // 啓用熱更新的第一步
},
plugins:[ //配置插件的節點,熱更新的第2步
new webpack.HotModuleReplacementPlugin() //new 一個熱更新的模塊對象,這是啓用熱更新的第3步
]
複製代碼
插件做用:
插件用法:
安裝 html-webpack-plugin插件
npm i html-webpack-plugin -D
複製代碼
在webpack.config.js文件中添加插件
//webpack.config.js
const htmlWebpackPlugin = require('html-webpack-plugin')
plugins:[
new htmlWebpackPlugin({ //建立一個在內存中生成html頁面的插件
template:path.join(__dirname,'./src/index.html'),//指定模版頁面,未來會根據指定的頁面路徑,去生成內存中的頁面
filename:'index.html'
})
]
複製代碼
實際展現:
npm install module_name -S 即 npm install module_name –save 寫入dependencies
npm install module_name -D 即 npm install module_name –save-dev 寫入devDependencies
npm install module_name -g 全局安裝(命令行使用)
npm install module_name 本地安裝(將安裝包放在 ./node_modules 下)
dependencies與devDependencies有什麼區別呢?
注意:Webpack默認只能打包處理Js類型的文件,沒法處理其它的非Js類型的文件
若是要處理非Js類型的文件,咱們須要手動安裝一些合適的第三方loader加載器
打包處理CSS文件:安裝 style-loader css-loader
npm i style-loader css-loader -D
複製代碼
在webpack.config.js
配置文件裏面新增module
節點對象,在這個module
對象身上,有個rules
屬性數組,這個數組中,存放了全部的第三方文件愛你的匹配和處理規則
module:{ //這個節點,用來配置全部第三方模塊加載器
rules:[ //配置第三方模塊的匹配規則
{test:/\.css$/,use:['style-loader','css-loader']} //配置處理 .css文件的第三方loader規則
]
}
複製代碼
在main.js入口文件裏面引入CSS文件便可成功使用
import './css/index.css'
複製代碼
問題描述:
Webpack
沒法處理CSS
文件中的URL地址,不管是圖片仍是字體庫,只要是URL,都處理不了解決方法:
經過安裝 url-loader file-loader
插件來對URL進行處理
npm i url-loader file-loader -D
複製代碼
使用步驟
安裝 url-loader file-loader
插件
在webpack.config.js
文件裏面配置URL的處理規則
base64
格式的字符串, 若是 圖片小於給定的 limit 值,則會被轉爲 base64
的字符串//URL圖片路徑的匹配規則
{test:/\.(jpg|jepg|png|gif)$/,use:'url-loader?limit=1000&name=[hash:8]-[name].[ext]'},
//字體圖標的匹配規則
{test:/\.(eot|svg|woff|woff2|ttf)$/,use:'url-loader'}
複製代碼
- 先校驗文件類型,若是是js文件直接打包
- 若是非js文件,拿到後綴名,去webpack.config.js裏面找對應匹配規則
- 找到則調用規則打包,不然報錯
- rules的use規則數組從右到左調用,會將後面調用完畢的處理結果交給前面的規則繼續處理
- 調用完畢以後會將處理結果直接交給Webpack進行打包合併,最終輸出到bundle.js中去
示例:
css-loader
插件進行處理,將處理結果交給style-loader
繼續處理module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader'] }
]
}
複製代碼
因爲Webpack
默認只能打包處理Js
類型的文件,沒法處理其它的非Js
類型的文件,因此若是要處理非Js
類型的文件,咱們須要手動安裝一些合適的第三方loader
加載器。
安裝並使用第三方加載器的方法爲如下幾步
//添加module對象
//在module對象裏面添加rules數組
//在rules數組裏面添加相對應文件的匹配規則
module:{
rules:[
{test:/\.css$/,use:['style-loader','css-loader']}
]
}
複製代碼
CSS
或者其它文件,都以import
命令的方式在入口js
文件裏面引入完成以上步驟便可成功啓用loader加載器
在
Webpack
中,默認只能處理一部分ES6
語法,一些更高級的ES6
或者ES7
語法,Webpack
是處理不了的,這時候,就須要藉助第三方loader,來幫助Webpack
處理這些高級的語法,當第三方loader把高級語法轉爲低級的語法以後,會把結果交給Webpack
去打包到bundle.js
中經過Babel,能夠幫助咱們將高級語法轉換爲低級的語法
cnpm i babel-core babel-loader babel-plugin-transform-runtime -D
cnpm i bebel-preset-env babel-preset-stage-0 -D
在Webpack.config.js配置文件中,在module節點下的rules數組中添加一個新的匹配規則
注意:
{test:/\.js$/,use:'babel-loader',exclude:/node_modules/}
複製代碼
在項目的根目錄中,新建一個叫作 .babelrc
的Babel配置文件
json
格式,必須複覈JSON
語法規範,不能寫註釋,字符串必須使用雙引號babel-plugin-transfrom
babel-preset-env,babel-preset-stage-0
{
"presets":["env","stage-0"],
"plugins":["transform-runtime"]
}
複製代碼
完成以上配置,便可在項目中使用ES6語法,能夠編寫一個Class類,設置靜態屬性並打印它們來測試
傳統的Vue使用方式
- 經過 script標籤引入 vue.js文件
- 在body中聲明一個盒子,而且爲它設置一個id屬性
- 在script標籤中經過new Vue()建立一個VM實例
當咱們使用 import命令導入模塊中的一個包的時候,它的查找規則是怎樣的呢
- 找項目目錄中有沒有 node_modules 的文件夾
- 在node_modules文件夾中找到對應的包名
- 在package.json的配置文件裏面,找到一個main屬性【main屬性指定了這個包在被加載的時候的入口文件】
接下來咱們來試着導入一個vue包,並查看它對應的入口文件
安裝 npm i vue -D
導入包 import Vue form 'vue'
查看 node_modules/vue/package.json中的main屬性,看它的入口文件是哪一個
"main": "dist/vue.runtime.common.js",
複製代碼
仔細回想一下,咱們平時導入的是這個文件嗎?顯然不是,咱們平時導入的是vue.js文件,那這裏爲何會不同呢?帶着這個疑問,咱們繼續
以下都是一些簡單的代碼模版,這裏用代碼說明,不作具體解釋
//main.js 入口文件
//此處導入的是 vue.runtime.common.js
import Vue from 'vue'
var login = {
template:`<h1>Login success</h1>`
}
var vm = new Vue({
el:'#app',
data () {
return {
msg:'hello'
}
},
components:{
login
}
})
複製代碼
//index.html
<body>
<div id="app">
<p>{{msg}}</p>
<login></login>
</div>
</body>
複製代碼
運行,查看結果
錯誤分析
將模版預編譯爲渲染函數(使用render函數渲染模版)
渲染函數的使用,詳情請看這裏:Render函數的使用
經過嘗試,發現把組件寫在入口文件裏面並不能達到目標,因而,咱們抽取vue模版,經過vue文件來建立模版
建立 login.vue文件
<template>
<div>
<h1>
這是經過 vue 文件建立的模版
</h1>
</div>
</template>
<script>
</script>
<style>
</style>
複製代碼
安裝加載.vue文件的插件,並配置webpack.config.js
cnpm i vue-loader vue-template-compiler -D
複製代碼
//webpack.config.js
const vueLoaderPlugin =require('vue-loader/lib/plugin')
plugins:[
new vueLoaderPlugin()
],
module:{
rules:[
{test:/\.vue$/,use:'vue-loader'}, //處理.vue文件
]
},
複製代碼
在入口文件裏面引入 login.vue,並使用render函數渲染
import Vue from 'vue'
import login from './login.vue'
var vm = new Vue({
el:'#app',
data () {
return {
msg:'hello'
}
},
// render:function(createElement){
// return createElement(login)
// },
//簡寫
render:c => c(login)
})
複製代碼
再次運行,發現運行成功
用包含編譯器的構建(即完整的vue.js文件)
修改原始導入的vue.runtime.common.js,將引入的包修改成vue.js
import Vue from '../node_modules/vue/dist/vue.js'
import Vue form 'vue'
,可是須要在 webpack.config.js文件中增長以下配置resolve:{
alias:{
"vue$":"vue/dist/vue.js"
}
}
複製代碼
npm i vue -S
npm i vue-loader vue-template-complier -D
Import Vue from 'vue'
Import login from './login.vue'
命令導入這個組件安裝 vue-router依賴模塊
npm i vue -S
npm i vue-router -S
複製代碼
在main.js中引入Vue 和 vue-router模塊,並顯示的調用vue-router
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
複製代碼
在src目錄下建立App.vue主頁面模版文件
<template>
<div>
<h1>APP組件</h1>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
複製代碼
在 index文件中 建立一個 id 屬性等於 app
的div元素
在src
目錄下面新建文件夾,並在新建的文件夾下面建立login.vue
和register.vue
文件
將login.vue
和register.vue
組件應用到app
主頁模板上面去
<template>
<div>
<h1>APP組件</h1>
<router-link to='/login'>Login</router-link>
<router-link to='/register'>Register</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
複製代碼
在main.js
文件中配置路由,建立VM
實例,掛載app
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import app from './App.vue'
import login from './comp1/login.vue'
import register from './comp1/register.vue'
var router = new VueRouter({
routes:[
{path:'/login',component:login},
{path:'/register',component:register}
]
})
var vm = new Vue({
el:'#app',
render: c => c(app),
router
})
複製代碼
完成以上配置,啓動項目便可
在Webpack中使用路由的嵌套和在Vue中使用路由的嵌套基本相似
在路由基本使用的前提下,建立兩個新的組件 account,money
在login組件中添加這兩個組件的 ,並添加容器
<template>
<div>
<h1>Login success</h1>
<router-link to='/login/account'>Account</router-link>
<router-link to='/login/money'>Money</router-link>
<router-view></router-view>
</div>
</template>
複製代碼
在路由配置中給login添加children屬性,配置account,money路由便可
var router = new VueRouter({
routes:[
{path:'/login',component:login,children:[
{path:'account',component:account},
{path:'money',component:money},
]},
{path:'/register',component:register}
]
})
複製代碼
爲避免入口文件 main.js裏面的內容過多,咱們推薦使用抽離路由的方式,爲router單首創建一個文件夾
在src目錄下建立 router.js
import VueRouter from 'vue-router'
import login from './comp1/login.vue'
import register from './comp1/register.vue'
import account from './comp2/account.vue'
import money from './comp2/money.vue'
var router = new VueRouter({
routes:[
{path:'/login',component:login,children:[
{path:'account',component:account},
{path:'money',component:money},
]},
{path:'/register',component:register}
]
})
export default router
複製代碼
在main.js入口文件中,引入router.js暴露router對象,掛載到app便可
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import app from './App.vue'
import router from './router.js'
var vm = new Vue({
el:'#app',
render: c => c(app),
router
})
複製代碼
scoped屬性:
lang屬性:
在 .vue文件中,默認只能使用普通的 css樣式語法,若是想要使用 scss,或者 less語法樣式,須要給style標籤設置 lang屬性,而且指定具體的使用語法
<style lang='less'>
</style>
複製代碼