10.使用webpack

1.高效的開(kāi)發(fā)離不開(kāi)基礎(chǔ)工程的搭建。
2.近幾年來(lái)破托,前端的工作早已不再是切圖那么簡(jiǎn)單肪跋,項(xiàng)目比較大時(shí),可能會(huì)多人協(xié)同開(kāi)發(fā)土砂。模塊化州既、組件化谜洽、CSS預(yù)編譯等概念也成了經(jīng)常討論的話(huà)題。
前端自動(dòng)化(半自動(dòng)化)工程主要解決以下問(wèn)題:

  • JavaScript吴叶、CSS代碼的合并和壓縮
  • CSS 預(yù)處理:Less阐虚、Sass、Stylus的編譯
  • 生成雪碧圖(CSS Sprite)
  • ES6 轉(zhuǎn) ES5
  • 模塊化
    3.webpack打包后的代碼蚌卤,已經(jīng)不只是你寫(xiě)的代碼实束,其中夾雜了很多webpack自身的模塊處理代碼。因此造寝,學(xué)習(xí)webpack最難的是理解“編譯”這個(gè)概念磕洪,否則會(huì)一直存在一個(gè)疑問(wèn):為什么要這樣做吭练?
    4.在業(yè)務(wù)中寫(xiě)的各種格式的文件诫龙,比如typescript、less鲫咽、jpg签赃,還有本章后面要介紹的.vue格式的文件。這些格式的文件通過(guò)特定的加載器(Loader)編譯后分尸,最終統(tǒng)一生成為.js锦聊、.css、.png等靜態(tài)資源文件箩绍。在webpack的世界里孔庭,一張圖片、一個(gè)css甚至一個(gè)字體材蛛,都稱(chēng)為模塊(Module)圆到,彼此存在依賴(lài)關(guān)系,webpack就是來(lái)處理模塊間的依賴(lài)關(guān)系的卑吭,并把它們進(jìn)行打包芽淡。
    舉一個(gè)簡(jiǎn)單的例子,平時(shí)加載CSS大多通過(guò)<link>標(biāo)簽引入CSS文件,而在webpack里,直接在一個(gè).js文件中導(dǎo)入弓柱,比如:
    import 'src/styles/index.css';
    import 是 ES2015的語(yǔ)法钞钙,這里也可以寫(xiě)成 require('src/styles/index.css')。在打包時(shí)谅年,index.css會(huì)被打包進(jìn)一個(gè)js文件里,通過(guò)動(dòng)態(tài)創(chuàng)建<style>的形式來(lái)加載css樣式,當(dāng)然也可以進(jìn)一步配置纹笼,在打包編譯時(shí)把所有的css都提取出來(lái),生成一個(gè)css的文件苟跪。
    5.webpack的主要使用場(chǎng)景是單頁(yè)面富應(yīng)用(SPA)廷痘。SPA通常是由一個(gè)html文件和一堆按需加載的js組成蔓涧,它的html結(jié)構(gòu)可能會(huì)非常簡(jiǎn)單,比如:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>webpack app</title>
    <link rel="stylesheet" href="dist/main.css">
</head>
<body>
 <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
 <div id="app"></div>

<script type="text/javascript" src="dist/main.js"></script>

</body>
</html>

只有一個(gè)<div>節(jié)點(diǎn)笋额,所有的代碼都集成在了main.js文件中元暴,理論上它可以實(shí)現(xiàn)像知乎、淘寶這樣大型的項(xiàng)目兄猩。
6.在開(kāi)始講解webpack的用法前茉盏,先介紹兩個(gè)ES6 中的語(yǔ)法export和import,后面會(huì)大量使用枢冤。export和import是用來(lái)導(dǎo)出和導(dǎo)入模塊的鸠姨。一個(gè)模塊就是一個(gè)js文件,它擁有獨(dú)立的作用域淹真,里面定義的變量外部是無(wú)法獲取的讶迁。比如將一個(gè)配置文件作為模塊導(dǎo)出,示例代碼如下:

// config.js
var Config = {
  version:'1.0.0'
};
export { Config };
// 或者 config.js
export var Config = {
  version: '1.0.0'
};
//其他類(lèi)型(比如函數(shù)核蘸、數(shù)組巍糯、常量等)也可導(dǎo)出,比如導(dǎo)出一個(gè)函數(shù):
// add.js
export function add(a,b){
  return a + b;
};
//模塊導(dǎo)出后客扎,在需要使用模塊的文件使用import再導(dǎo)入祟峦,就可以在這個(gè)文件內(nèi)使用這些模塊了。示例代碼:
//main.js
import {Config } from './config.js';
import { add } from './add.js';
console.log(Config); //{version : '1.0.0'}
console.log(add(1,1)); //2

以上幾個(gè)示例中徙鱼,導(dǎo)入的模塊名稱(chēng)都是在export的文件中設(shè)置的宅楞,也就是說(shuō)用戶(hù)必須預(yù)先知道這個(gè)名稱(chēng)叫什么,比如Config袱吆、add厌衙。而有的時(shí)候,用戶(hù)不想去了解名稱(chēng)是什么杆故,只是把模塊的功能拿來(lái)使用迅箩,或者想自定義名稱(chēng),這是可以使用export default 來(lái)輸出默認(rèn)的模塊处铛。示例代碼:

//config.js
export default {
  version:'1.0.0'
};
//add.js
export default function(a,b){
  return a + b ;
}
//main.js
import conf from './config.js';
import Add from './add.js';
console.log(conf); // {version:'1.0.0'}
console.log(Add(1,1)); // 2
//如果使用npm安裝了一些庫(kù)饲趋,在webpack中可以直接導(dǎo)入,示例:
import Vue from 'vue';
import $ from 'jquery';

上例分別導(dǎo)入了Vue和jQuery的庫(kù)撤蟆,并且命名為Vue和$奕塑,在這個(gè)文件中就可以使用這兩個(gè)模塊。export 和 import 還有其他的用法家肯,這里不做太詳細(xì)的介紹龄砰。
7.安裝webpack與 webpack-dev-server。確保意境安裝了最新的Node.js和NPM,并已經(jīng)了解NPM的基本用法换棚。

首先式镐,創(chuàng)建一個(gè)目錄,比如demo固蚤,使用NPM初始化配置:
npm init
執(zhí)行后娘汞,會(huì)有一些列選項(xiàng),可以按回車(chē)鍵快速確認(rèn)夕玩,完成后會(huì)在demo目錄生產(chǎn)一個(gè)package.json的文件你弦。
之后在本地局部安裝webpack:
npm install webpack --save-dev
--save-dev 會(huì)作為開(kāi)發(fā)依賴(lài)來(lái)安裝webpack。安裝成功后燎孟,在package.json中會(huì)多一項(xiàng)配置:
"devDependencies":{
"webpack" : "^2.3.2"
}
接著需要安裝webpack-dev-server禽作,它可以在開(kāi)發(fā)環(huán)境中提供很多服務(wù),比如啟動(dòng)一個(gè)服務(wù)器揩页、熱更新旷偿、接口代理等,配置起來(lái)也很簡(jiǎn)單碍沐。同樣狸捅,在本地局部安裝:
npm install webpack-dev-server --save-dev
安裝完成后衷蜓,最終的package.json文件內(nèi)容為:

{
  "name" : "demo",
  "version" : "1.0.0",
  "description" : "",
  "main" : "index.js",
  "scripts" : {
    "test" : "echo \"Error : no test specified \" && exit 1"
  },
  "author" : "",
  "license" : "ISC",
  "devDependencies" : {
    “webpack” : "^2.3.2",
    "webpack-dev-server" : "^2.4.2"
  }
}

如果devDependencies中包含 webpack 和 webpack-dev-server累提,那么已經(jīng)安裝成功。
8.webpack核心概念磁浇。webpack就是一個(gè).js配置文件斋陪,你的架構(gòu)好或差都體現(xiàn)在這個(gè)配置里,隨著需求的不斷出現(xiàn)置吓,工程配置也是逐漸完善的无虚。

首先,在目錄DEMO 下創(chuàng)建一個(gè)js文件:webpack.config.js衍锚,并初始化它的內(nèi)容:
var config = {
};
module.exports = config;
這里的 module.exports = config; 相當(dāng)于 export default config;
由于目前還沒(méi)有安裝支持ES6的編譯插件友题,因此不能直接使用ES6的語(yǔ)法,否則會(huì)報(bào)錯(cuò)戴质。
然后在package.json的scripts里增加一個(gè)快速啟動(dòng)webpack-dev-server服務(wù)的腳本:
{
//...
"scripts" : {
"test" : "echo "Error: no test specified " && exit 1",
"dev" : "webpack-dev-server --config webpack.config.js"
},
//...
}
當(dāng)運(yùn)行 npm run dev 命令時(shí)度宦,就會(huì)執(zhí)行
webpack-dev-server --open --config webpack.config.js 命令。
其中告匠,--config 是指向 webpack-dev-server 讀取的配置文件路徑戈抄,這里直接讀取我們?cè)谏弦徊絼?chuàng)建的 webpack.config.js 文件。
--open 會(huì)在執(zhí)行命令時(shí)自動(dòng)在瀏覽器打開(kāi)頁(yè)面后专,默認(rèn)地址是 127.0.0.1:8080划鸽,不過(guò)IP和端口號(hào)都是可以配置的,如:

{
  "scripts" : {
    "dev" : "webpack-dev-server  --host  172.172.172.1 --port 8888 --open --config webpack.config.js"
  }
}

這樣訪問(wèn)地址就改為了 172.172.172.1:8888。一般在局域網(wǎng)下裸诽,需要讓其他同事訪問(wèn)時(shí)可以這樣配置嫂用。

webpack配置中最重要也是必選的兩項(xiàng)是入口(Entry)和 出口(Output)。入口的作用是告訴webpack從哪里開(kāi)始尋找依賴(lài)丈冬,并且編譯尸折,出口則用來(lái)配置編譯后的文件存儲(chǔ)位置和文件名。
在demo目錄下新建一個(gè)空的main.js作為入口的文件殷蛇,然后在webpack.config.js中進(jìn)行入口和輸出的配置:

var path = require('path');
var config = {
  entry:{
    main : './main'  
  },
  output:{
    path : path.join(_dirname, './dist'),
    publicPath : '/dist/',
    filename : 'main.js'
  }
};
module.exports = config;

entry中的main就是我們配置的單入口实夹。webpack會(huì)從main.js文件開(kāi)始工作。output中path選項(xiàng)用來(lái)存放打包后的輸出目錄粒梦,是必填項(xiàng)亮航。publicPath指定資源文件引用的目錄,如果你的資源存放在CDN上匀们,這里可以填CDN的網(wǎng)址缴淋。filename用于指定輸出文件的名稱(chēng)。因此泄朴,這里配置的output意為打包后的文件會(huì)存儲(chǔ)為 demo/dist/main.js 文件重抖,只要在html 中引入它就可以了。在demo目錄下祖灰,新建一個(gè)index.html 作為我們 SPA 的入口:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>webpack APP</title>
</head>
<body>
    <div id="app">
        Hello World.
    </div>
    <script type="text/javascript" src="/dist/main.js"></script>
</body>
</html>

在終端執(zhí)行如下命令钟沛,就會(huì)自動(dòng)在瀏覽器中打開(kāi)頁(yè)面:

npm run dev

打開(kāi)dome/main.js文件,添加一行JavaScript代碼來(lái)修改頁(yè)面內(nèi)容:

document.getElementById('app').innerHTML = 'Hello webpack.';

保存文件局扶,回到剛才打開(kāi)的頁(yè)面恨统,發(fā)現(xiàn)頁(yè)面內(nèi)容已經(jīng)變?yōu)榱恕癏ello webpack”。注意三妈,此時(shí)并沒(méi)有刷新瀏覽器畜埋,就已經(jīng)自動(dòng)更新了,這就是webpack-dev-server 的熱更新功能畴蒲,它通過(guò)建立一個(gè)WebSocket 連接來(lái)實(shí)時(shí)響應(yīng)代碼的修改悠鞍。
9.學(xué)習(xí)webpack最難的是理解它“編譯”的概念。我們通過(guò)chrom瀏覽器開(kāi)發(fā)者工具的network視圖查看webpack編譯出的 /dist/main.js 文件模燥】Ъ溃可以看到有400多行。這里面很多都是webpack-dev-server的功能涧窒,只在開(kāi)發(fā)時(shí)有效心肪,生產(chǎn)環(huán)境下編譯就不會(huì)這么臃腫了。執(zhí)行下面的命令打包:

webpack --progress --hide-modules

這是會(huì)生成一個(gè) demo/dist/main.js 文件纠吴,只有很少的行數(shù)硬鞍。
10.上面通過(guò)配置入口(entry)和出口(Output)已經(jīng)可以啟動(dòng)webpack項(xiàng)目了,不過(guò)這并不是webpack的特點(diǎn),如果它只有這些功能固该,根本就不用這么麻煩锅减。webpack.config.js可以進(jìn)一步配置,來(lái)實(shí)現(xiàn)更強(qiáng)大的功能伐坏。
在webpack的世界里怔匣,每個(gè)文件都是一個(gè)模塊,比如.css桦沉、.js每瞒、.html、.jpg纯露、.less等剿骨。對(duì)于不同的模塊,需要用不同的加載器(Loaders)來(lái)處理埠褪,而加載器就是webpack最重要的功能浓利。通過(guò)安裝不同的加載器可以對(duì)各種后綴名的文件進(jìn)行處理,比如要寫(xiě)一些CSS樣式钞速,就要用到style-loader 和 css-loader贷掖。下面就通過(guò)NPM 來(lái)安裝它們:

npm install css-loader --save-dev
npm install style-loader --save-dev

安裝完成后,在webpack.config.js 文件里配置Loader渴语,增加對(duì).css 文件的處理:

var config = {
  //...
  module:{
    rules:[
      {
        test: /\.css$/,
        use:[
          'style-loader',
          'css-loader'
        ]
      }
    ]
  }
};
module.exports = config;

在module對(duì)象的rule屬性中可以指定一系列的loaders苹威,每一個(gè)loader都必須包含test和use兩個(gè)選項(xiàng)。這段配置的意思是說(shuō)遵班,當(dāng)webpack編譯過(guò)程中遇到 require()或 import 語(yǔ)句導(dǎo)入一個(gè)后綴名為 .css 的文件時(shí)屠升,先將它通過(guò) css-loader轉(zhuǎn)換潮改,再通過(guò)style-loader 轉(zhuǎn)換狭郑,然后繼續(xù)打包。 use選項(xiàng)的值可以是數(shù)組或字符串汇在,如果是數(shù)組翰萨,它的編譯數(shù)序就是從后往前。
在demo目錄下新建一個(gè)style.css的文件糕殉,并在main.js中導(dǎo)入:

/* style.css */
#app{
    font-size:24px;
    color:#f50;
}
// main.js
import './style.css';
document.getElementById('app').innerHTML = 'Hello webpack.';

重新執(zhí)行npm run dev 命令亩鬼,可以看到頁(yè)面中的文字已經(jīng)變成紅色,并且字號(hào)也變大了阿蝶。
11.可以看到雳锋,CSS是通過(guò)JavaScript動(dòng)態(tài)創(chuàng)建 <style> 標(biāo)簽來(lái)寫(xiě)入的,這意味著樣式代碼都已經(jīng)編譯在了main.js文件里羡洁,但在實(shí)際業(yè)務(wù)中玷过,可能并不希望這樣做,因?yàn)轫?xiàng)目大了樣式會(huì)很多,都放在JS里太占體積辛蚊,還不能做緩存粤蝎。這是要用到webpack的一個(gè)重要概念——插件(Plugins)
webpack的插件功能很強(qiáng)大袋马,而且可以定制初澎。這里我們使用一個(gè) extract-text-webpack-plugin的插件來(lái)把散落在各地的css提取出來(lái),并生成一個(gè)main.css 的文件虑凛,最終在index.html里通過(guò)<link>的形式加載它碑宴。
通過(guò)NPM安裝 extract-text-webpack-plugin 插件:
npm install extract-text-webpack-plugin --save-dev
然后在配置文件中導(dǎo)入插件,并改寫(xiě)loader的配置:

//導(dǎo)入插件
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var config = {
  //...
  module:{
    rules:[
      {
        test: /\.css$/,
        use:ExtractTextPlugin.extract({
           use:'css-loader',
           fallback:'style-loader' 
        })
      }
    ]
  },
  plugins:[
    //重命名提取后的css文件
    new ExtractTextPlugin("main.css")
  ]
};
module.exports = config ;

// index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>webpack APP</title>
    <link rel="stylesheet" type="text/css" href="/dist/main.css">
</head>
.....

插件還可以進(jìn)行豐富的配置桑谍。重啟服務(wù)后墓懂,就可以看到<style>已經(jīng)沒(méi)有了,通過(guò)<link>引入的main.css 文件已經(jīng)生效霉囚。
webpack 雖然概念比較新捕仔,看似復(fù)雜,但它只不過(guò)是一個(gè)js配置文件盈罐,只要搞清楚入口(Entity)榜跌,出口(Output)、加載器(Loaders)和 插件(Plugins)這4個(gè)概念盅粪,使用起來(lái)就不那么困惑了钓葫。
12.單文件組件。之前票顾,在字符串模版template選項(xiàng)里拼寫(xiě)字符串DOM非常費(fèi)勁础浮,尤其是用""換行。Vue.js是一個(gè)漸進(jìn)式的JavaScript框架奠骄,在使用webpack 構(gòu)建Vue 項(xiàng)目時(shí)豆同,可以使用一種新的構(gòu)建模式:.vue 單文件組件。.vue 單文件組件就是一個(gè)后綴名為.vue 的文件含鳞,在webpack中使用vue-loader 就可以對(duì).vue 格式的文件進(jìn)行處理影锈。
一個(gè) .vue 文件一般包含3部分,即 <template>蝉绷、<script> 和 <style>鸭廷,如下所示:

<template>
    <div>你好:{{ name }}</div>
</template>
<script>
export default {
    props:{
        name:{
            type:String,
            default:''
        }
    }
}
</script>

<style scoped>
    div{
        color:#f60;
    }
</style>

在component.vue 文件中,<template></template>之間的代碼就是該組件的模板HTML熔吗,<style></style>之間的是CSS樣式辆床,示例中的<style>標(biāo)簽使用了scoped屬性,表示當(dāng)前的CSS只在這個(gè)組件有效桅狠,如果不加讼载,那么div的樣式會(huì)用到整個(gè)項(xiàng)目宵晚。<style>還可以結(jié)合CSS預(yù)編譯一起使用,比如使用 Less處理可以寫(xiě)成 <style lang="less">维雇。
13.使用.vue 文件需要先安裝 vue-loader淤刃、vue-style-loader 等加載器并做配置。因?yàn)橐褂肊S6 語(yǔ)法吱型,還需要安裝babel 和 babel-loader等加載器逸贾。
使用npm 逐個(gè)安裝以下依賴(lài):

npm install --save vue
npm install --save-dev vue-loader
npm install --save-dev vue-style-loader
npm install --save-dev vue-template-compiler
npm install --save-dev vue-hot-reload-api
npm install --save-dev babel
npm install --save-dev babel-loader
npm install --save-dev babel-core
npm install --save-dev babel-plugin-transform-runtime
npm install --save-dev babel-preset-es2015
npm install --save-dev babel-runtime

安裝完成后,修改配置文件webpack.config.js來(lái)支持對(duì) .vue文件及ES6的解析:

var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var config = {
  entry:{
    main : './main'  
  },
  output:{
    path : path.join(__dirname, './dist'),
    publicPath : '/dist/',
    filename : 'main.js'
  },
  module:{
    rules:[
      {
        test:/\.vue$/,
        loader:'vue-loader',
        options:{
          loaders:{
            css:ExtractTextPlugin.extract({
              use:'css-loader',
              fallback:'vue-style-loader'
            })
          }
        }
      },
      {
        test:/\.js$/,
        loader:'babel-loader',
        exclude:/node_modules/
      },
      {
        test: /\.css$/,
          use:ExtractTextPlugin.extract({
            use:'css-loader',
            fallback:'style-loader' 
          })
      }
    ]
  },
  plugins:[
    //重命名提取后的css文件
    new ExtractTextPlugin("main.css")
  ]
};
module.exports = config;

vue-loader 在編譯.vue 文件時(shí)津滞,會(huì)對(duì)<template>铝侵、<script>、<style> 分別處理触徐,所以在vue-loader選項(xiàng)里多了一項(xiàng)options來(lái)進(jìn)一步對(duì)不同語(yǔ)言進(jìn)行配置咪鲜。比如在對(duì) css進(jìn)行處理時(shí),會(huì)先通過(guò)css-loader解析撞鹉,然后把處理結(jié)果再交給 vue-style-loader 處理疟丙。當(dāng)你的技術(shù)棧多樣化時(shí),可以給<template>鸟雏、<script>享郊、<style> 都指定不同的語(yǔ)言,比如<template lang="jade"> 和 <style lang="less"> 孝鹊, 然后配置loaders就可以了炊琉。
在demo目錄下新建一個(gè)名為.babelrc的文件,并寫(xiě)入babel的配置又活,webpack 會(huì)依賴(lài)此配置文件來(lái)用babel 編譯ES6 代碼:

{
  "presets" : ["es2015"],
  "plugins" : ["transform-runtime"],
  "comments" : false
}

配置好這些后苔咪,就可以使用.vue 文件了。
每個(gè).vue 文件就代表一個(gè)組件柳骄,組件之間可以相互依賴(lài)团赏。
在工程目錄下新建一個(gè)app.vue的文件并寫(xiě)入以下內(nèi)容:

<template>
    <div> Hello {{name}} </div>
</template>
<script>
export default {
    data(){
        return {
            name: 'Vue.js'
        }
    }
}
</script>
<style scoped>
    div{
        color:#f60;
        font-size:24px;
    }
</style>

ES 6 語(yǔ)法提示:data () { } 等同于 data:function() { }
在<template>內(nèi)寫(xiě)的HTML寫(xiě)法完全同html文件,webpack最終會(huì)把它編譯為Render 函數(shù)的形式夹界。寫(xiě)在<style>里的樣式馆里,我們已經(jīng)用插件 extract-text-webpack-plugin 配置過(guò)了,最終會(huì)統(tǒng)一提取并打包在main.css 里可柿,因?yàn)榧恿藄cope 屬性,這部分樣式只會(huì)對(duì)當(dāng)前組件app.vue 有效丙者。
.vue 的組件是沒(méi)有名稱(chēng)的复斥,在父組件使用時(shí)可以對(duì)它自定義。寫(xiě)好了組件械媒,就可以在入口main.js 中使用它了目锭。打開(kāi)main.js 文件评汰,把內(nèi)容替換為下面的代碼:

// 導(dǎo)入 Vue 框架
import Vue from 'vue';
// 導(dǎo)入 app.vue 組件
import App from './app.vue';
// 創(chuàng)建 Vue 根實(shí)例
new Vue({
  el: '#app',
  render: h=> h (App)
})

執(zhí)行命令npm run dev,第一個(gè)Vue 工程就跑起來(lái)了痢虹。
打開(kāi)chrome調(diào)試工具被去,在elements 面板可以看到,<div id="app"> 已經(jīng)被組件替換成了:

<div data-v-381730fa> Hello Vue.js </div>

// 對(duì)應(yīng)的main.css 為:
div[data-v-381730fa]{
    color:#f60;
    font-size:24px;
}

之所以多了一串data-v-xxx 的內(nèi)容奖唯,是因?yàn)槭褂昧?lt;style scoped>的功能惨缆,如果去掉 scoped,就只剩下 <div> Hello Vue.js </div> 了丰捷。

解決npm 慢的問(wèn)題
可用 get命令查看registry
npm congfig get registry
原版結(jié)果為
http://registry.npmjs.org
用set命令換成阿里的鏡像就可以了
npm config set registry https://registry.npm.taobao.org
在執(zhí)行命令
npm install

接下來(lái)坯墨,在demo目錄下,再新建兩個(gè)文件title.vue 和 button.vue

// title.vue:
<template>
    <h1>
        <a :href="'#' + title "> {{ title }} </a>
    </h1>
</template>
<script>
export default {
    props:{
        title:{
            type:String
        }
    }
}
</script>
<style scoped>
    h1 a{
        color:#3399ff;
        font-size:24px;
    }
</style>

// button.vue:
<template>
    <button @click="handleClick" :style="styles">
        <slot></slot>
    </button>
</template>
<script>
export default {
    props:{
        color:{
            type:String,
            default:'#00cc66'
        }
    },
    computed:{
        styles(){
            return {
                background:this.color
            }
        }
    },
    methods:{
        handleClick(e){
            this.$emit('click',e);
        }
    }
}
</script>
<style scoped>
    button{
        border:0;
        outline:none;
        color:#fff;
        padding:4px 8px;
    }
    button:active{
        position:relative;
        top:1px;
        left:1px;
    }
</style>

改寫(xiě)根實(shí)例 app.vue 組件病往,把title.vue 和 button.vue 導(dǎo)入進(jìn)來(lái):

<template>
    <div>        
        <v-title title="Vue組件化"></v-title>
        <v-button @click="handleClick">點(diǎn)擊按鈕</v-button>
    </div>
</template>
<script>
//導(dǎo)入組件
import vTitle from './title.vue';
import vButton from './button';

export default {
    components:{
        vTitle,
        vButton
    },
    methods:{
        handleClick(e){
            console.log(e);
        }
    }
}
</script>
<style scoped>
    div{
        color:#f60;
        font-size:24px;
    }
</style>

導(dǎo)入的組件都是局部注冊(cè)的捣染,而且可以自定義名稱(chēng),其他用法和組件一致停巷。后面會(huì)基于webpack和單文件組件展開(kāi)耍攘。

ES 6 語(yǔ)法提示:
=> 是箭頭函數(shù)
render: h=> h(App) 等同于:
render : function (h) {
return h (App)
}

components: {
vTitle,
vButton
}
等同于:
components:{
vTitle : vTitle,
vButton : vButton
}
對(duì)象字面量縮寫(xiě),當(dāng)對(duì)象的key 和 value 名稱(chēng)一致時(shí)畔勤,可以縮寫(xiě)成一個(gè)少漆。
14.用于生產(chǎn)環(huán)境。我們先對(duì)webpack 進(jìn)一步配置硼被,來(lái)支持更多常用的功能示损。安裝url-loader 和 file-loader 來(lái)支持圖片、字體等文件:

npm install --save-dev url-loader
npm install --save-dev file-loader

//webpack.config.js
var config = {
module:{
    rules:[
      {
        test:/\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/,
        loader:'url-loader?limit=1024'
      }
}

當(dāng)遇到.gif嚷硫、.png检访、.ttf 等格式文件時(shí),url-loader會(huì)把它們一起編譯到dist 目錄下仔掸," ?limit=1024" 是指如果這個(gè)文件小余1kb脆贵,就以base64的形式加載,不會(huì)生成一個(gè)文件起暮。
找一張圖片卖氨,保存為 demo/images/image.png,并在app.vue 中加載它:

<template>
    <div>        
        <v-title title="Vue組件化"></v-title>
        <v-button @click="handleClick">點(diǎn)擊按鈕</v-button>
        <p>
            <img src="./images/image.png" style="width:200px;">
        </p>
    </div>
</template>

--save 和 --save-dev
在安裝包時(shí), 我們可以根據(jù)環(huán)境決定包的安裝效果. 假設(shè)我們要安裝express
1.執(zhí)行 npm i express --save則表示我想在生產(chǎn)環(huán)境中使用express, 同時(shí), express的版本信息會(huì)被寫(xiě)入package.json中的dependencies屬性中.
2.而執(zhí)行npm i express --save-dev 表示我想在開(kāi)發(fā)和測(cè)試環(huán)境中使用. express的版本信息會(huì)被寫(xiě)入package.json中的devDependencies屬性中.
3 --save可以簡(jiǎn)寫(xiě)為-S, --save-dev可以簡(jiǎn)寫(xiě)為-D.

查看包版本:

查看本地安裝的包
D:\source_code\vue-book-master\chapter 10>npm ls babel-loader
chapter-10@1.0.0 D:\source_code\vue-book-master\chapter 10
`-- babel-loader@8.1.0
查看全局安裝的包
D:\source_code\vue-book-master\chapter 10>npm ls babel-loader -g
D:\develop_soft\nodejs\node_global
`-- (empty)

三個(gè)命令:
1.查看npm服務(wù)器上所有的包版本信息
npm view babel-loader versions
2.查看該包最新的版本是哪一個(gè)
npm view babel-loader version
3.可以查看該包所有版本负懦,以及更多的信息
npm info babel-loader
示例:

D:\source_code\vue-book-master\chapter 10>npm view babel-loader versions

[
  '4.0.0',         '4.1.0',        '4.2.0',         '4.3.0',
  '5.0.0',         '5.1.0',        '5.1.2',         '5.1.3',
  '5.1.4',         '5.2.0',        '5.2.1',         '5.2.2',
  '5.3.0',         '5.3.1',        '5.3.2',         '5.3.3',
  '5.4.0',         '5.4.1',        '5.4.2',         '6.0.0',
  '6.0.1',         '6.1.0',        '6.2.0',         '6.2.1',
  '6.2.2',         '6.2.3',        '6.2.4',         '6.2.5',
  '6.2.6',         '6.2.7',        '6.2.8',         '6.2.9',
  '6.2.10',        '6.3.0',        '6.3.1',         '6.3.2',
  '6.4.0',         '6.4.1',        '7.0.0-alpha.1', '7.0.0-alpha.2',
  '7.0.0-alpha.3', '7.0.0-beta.1', '7.0.0',         '7.1.0',
  '7.1.1',         '7.1.2',        '7.1.3',         '7.1.4',
  '7.1.5',         '8.0.0-beta.0', '8.0.0-beta.1',  '8.0.0-beta.2',
  '8.0.0-beta.3',  '8.0.0-beta.4', '8.0.0-beta.5',  '8.0.0-beta.6',
  '8.0.0',         '8.0.1',        '8.0.2',         '8.0.3',
  '8.0.4',         '8.0.5',        '8.0.6',         '8.1.0'
]


D:\source_code\vue-book-master\chapter 10>npm view babel-loader version
8.1.0

D:\source_code\vue-book-master\chapter 10>npm info babel-loader

babel-loader@8.1.0 | MIT | deps: 5 | versions: 64
babel module loader for webpack
https://github.com/babel/babel-loader

dist
.tarball: https://registry.npm.taobao.org/babel-loader/download/babel-loader-8.1.0.tgz
.shasum: c611d5112bd5209abe8b9fa84c3e4da25275f1c3

dependencies:
find-cache-dir: ^2.1.0 loader-utils: ^1.4.0   mkdirp: ^0.5.3         pify: ^4.0.1           schema-utils: ^2.6.5

maintainers:
- danez <daniel@tschinder.de>
- existentialism <bng412@gmail.com>
- hzoo <hi@henryzoo.com>
- loganfsmyth <loganfsmyth@gmail.com>

dist-tags:
latest: 8.1.0       next: 8.0.0-beta.6  old: 5.4.2

published 2 months ago by existentialism <bng412@gmail.com>

D:\source_code\vue-book-master\chapter 10>

15.介紹打包上線(xiàn)前筒捺,先來(lái)分析webpack打包后的產(chǎn)物有哪些。
本書(shū)所介紹和使用的都是單頁(yè)面富應(yīng)用(SPA)技術(shù)纸厉,這意味著最終只有一個(gè)html的文件系吭,其余都是靜態(tài)資源。實(shí)際部署到生產(chǎn)環(huán)境時(shí)颗品,一般會(huì)將html 掛在后端程序下肯尺,由后端路由渲染這個(gè)頁(yè)面沃缘,將頁(yè)面所有的靜態(tài)資源(css、js则吟、image槐臀、icon、font等)單獨(dú)部署到CDN氓仲,當(dāng)然也可以和后端程序部署在一起水慨,這樣就實(shí)現(xiàn)了前后端完全分離。
我們?cè)趙ebpack的output 選項(xiàng)里已經(jīng)指定了path 和 publicPath寨昙,打完包后讥巡,所有的資源都會(huì)保存在 demo/dist 目錄下。
打包會(huì)用到下面兩個(gè)依賴(lài)舔哪,使用NPM安裝:
npm install --save-dev webpack-merge
npm install --save-dev html-webpack-plugin
為了方便開(kāi)發(fā)和生產(chǎn)環(huán)境的切換欢顷,我們?cè)赿emo目錄下再新建一個(gè)用于生產(chǎn)環(huán)境的配置文件 webpack.prod.config.js。
編譯打包捉蚤,直接執(zhí)行webpack 命令就可以抬驴。在package.json中,再加入一個(gè)build的快捷腳本用來(lái)打包:

"scripts" : {
"dev" : "webpack-dev-server --open --config webpack.config.js",
"build" : "webpack --progress --hide-modules --config webpack.prod.config.js"
}

先來(lái)看一下webpack.prod.config.js的代碼:

var webpack = require('webpack');
var HtmlwebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var merge = require('webpack-merge');
var webpackBaseConfig = require('./webpack.config.js');
//清空基本配置的插件列表
webpackBaseConfig.plugins = [ ];
module.exports = merge(webpackBaseConfig,{
  output:{
    publicPath : '/dist/',
    //將入口文件重命名為帶有20位hash值的唯一文件
    filename: '[name].[hash].js'
  },
  plugins:[
    new ExtractTextPlugin({
      // 提取 css缆巧,并重命名為帶有20位hash值的唯一文件
      filename : '[name].[hash].css',
      allChunks : true
    }),
    // 定義當(dāng)前node 環(huán)境為生產(chǎn)環(huán)境
    new webpack.DefinePlugin({
      'process.env' : {
        NODE_ENV : '"production"'
      }
    }),
    // 壓縮js
    new webpack.optimize.UglifyJsPlugin({
      compress : {
        warnings : false
      }
    }),
    // 提取模板布持,并保存入口 html文件
    new HtmlWebpackPlugin({
      filename : '../index_prod.html',
      template : './index.ejs',
      inject : false
    })
  ]
});

上面安裝的 webpack-merge 模塊就是用于合并兩個(gè)webpack 的配置文件,所以prod 的配置是在webpack.config.js 基礎(chǔ)上擴(kuò)展的陕悬。靜態(tài)資源在大部分場(chǎng)景下都有緩存(304)题暖,更新上線(xiàn)后一般都希望用戶(hù)能及時(shí)地看到內(nèi)容,所以給打包后的css和js文件的名稱(chēng)都加了20位的hash值捉超。這樣文件名就唯一了(比如 main.b3dd20e2dae9d76af86b.js)胧卤,只要不對(duì)html文件設(shè)置緩存,上線(xiàn)后立即就可以加載最新的靜態(tài)資源拼岳。
html-webpack-plugin 是用來(lái)生成html 文件的枝誊,它通過(guò)template 選項(xiàng)來(lái)讀取指定的模板 index.ejs,然后輸出到filename 指定的目錄惜纸,也就是demo/index_prod.html叶撒。模板 index.ejs 動(dòng)態(tài)設(shè)置了靜態(tài)資源的路徑和文件名,代碼如下:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>webpack App</title>
  <link rel="stylesheet" href="<%= htmlwebpackPlugin.files.css[0] %>">
</head>
<body>
  <div id="app"></div>
  <script type="text/javascript" src="<%= htmlwebpackPlugin.files.js[0] %>"></script>
</body>
</html>

最后在終端運(yùn)行 npm run build耐版,等待一會(huì)就會(huì)完成打包祠够,成功后在demo下會(huì)生成一個(gè)dist的目錄,里面就是打包完的所有靜態(tài)資源椭更。

ejs 是一個(gè)JavaScript 模板庫(kù)哪审,用來(lái)從JSON 數(shù)據(jù)中生成HTML 字符串,常用于 Node.js虑瀑。

webpack除了上述內(nèi)容外湿滓,和有很多高級(jí)的配置和豐富的插件及加載器,可查閱webpack文檔:https://webpack.js.org/

本章代碼:https://github.com/icarusion/vue-book
vue-book 下的demo目錄下執(zhí)行 npm install 命令會(huì)自動(dòng)安裝所有的依賴(lài)舌狗,然后執(zhí)行 npm run dev 啟動(dòng)服務(wù)叽奥。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市痛侍,隨后出現(xiàn)的幾起案子朝氓,更是在濱河造成了極大的恐慌,老刑警劉巖主届,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赵哲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡君丁,警方通過(guò)查閱死者的電腦和手機(jī)枫夺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)绘闷,“玉大人橡庞,你說(shuō)我怎么就攤上這事∮≌幔” “怎么了扒最?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)华嘹。 經(jīng)常有香客問(wèn)我吧趣,道長(zhǎng),這世上最難降的妖魔是什么耙厚? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任强挫,我火速辦了婚禮,結(jié)果婚禮上颜曾,老公的妹妹穿的比我還像新娘纠拔。我一直安慰自己,他們只是感情好泛豪,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布稠诲。 她就那樣靜靜地躺著,像睡著了一般诡曙。 火紅的嫁衣襯著肌膚如雪臀叙。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天价卤,我揣著相機(jī)與錄音劝萤,去河邊找鬼。 笑死慎璧,一個(gè)胖子當(dāng)著我的面吹牛床嫌,可吹牛的內(nèi)容都是我干的跨释。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼厌处,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鳖谈!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起阔涉,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤缆娃,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后瑰排,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體贯要,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年椭住,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了崇渗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡函荣,死狀恐怖显押,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情傻挂,我是刑警寧澤乘碑,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站金拒,受9級(jí)特大地震影響兽肤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜绪抛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一资铡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧幢码,春花似錦笤休、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至贞铣,卻和暖如春闹啦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辕坝。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工窍奋, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓琳袄,卻偏偏與公主長(zhǎng)得像江场,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挚歧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348