10.使用webpack

1.高效的開發(fā)離不開基礎(chǔ)工程的搭建。
2.近幾年來,前端的工作早已不再是切圖那么簡單,項(xiàng)目比較大時,可能會多人協(xié)同開發(fā)。模塊化、組件化、CSS預(yù)編譯等概念也成了經(jīng)常討論的話題。
前端自動化(半自動化)工程主要解決以下問題:

  • JavaScript、CSS代碼的合并和壓縮
  • CSS 預(yù)處理:Less、Sass、Stylus的編譯
  • 生成雪碧圖(CSS Sprite)
  • ES6 轉(zhuǎn) ES5
  • 模塊化
    3.webpack打包后的代碼,已經(jīng)不只是你寫的代碼,其中夾雜了很多webpack自身的模塊處理代碼。因此,學(xué)習(xí)webpack最難的是理解“編譯”這個概念,否則會一直存在一個疑問:為什么要這樣做?
    4.在業(yè)務(wù)中寫的各種格式的文件,比如typescript、less、jpg,還有本章后面要介紹的.vue格式的文件。這些格式的文件通過特定的加載器(Loader)編譯后,最終統(tǒng)一生成為.js、.css、.png等靜態(tài)資源文件。在webpack的世界里,一張圖片、一個css甚至一個字體,都稱為模塊(Module),彼此存在依賴關(guān)系,webpack就是來處理模塊間的依賴關(guān)系的,并把它們進(jìn)行打包。
    舉一個簡單的例子,平時加載CSS大多通過<link>標(biāo)簽引入CSS文件,而在webpack里,直接在一個.js文件中導(dǎo)入,比如:
    import 'src/styles/index.css';
    import 是 ES2015的語法,這里也可以寫成 require('src/styles/index.css')。在打包時,index.css會被打包進(jìn)一個js文件里,通過動態(tài)創(chuàng)建<style>的形式來加載css樣式,當(dāng)然也可以進(jìn)一步配置,在打包編譯時把所有的css都提取出來,生成一個css的文件。
    5.webpack的主要使用場景是單頁面富應(yīng)用(SPA)。SPA通常是由一個html文件和一堆按需加載的js組成,它的html結(jié)構(gòu)可能會非常簡單,比如:
<!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>

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

// config.js
var Config = {
  version:'1.0.0'
};
export { Config };
// 或者 config.js
export var Config = {
  version: '1.0.0'
};
//其他類型(比如函數(shù)、數(shù)組、常量等)也可導(dǎo)出,比如導(dǎo)出一個函數(shù):
// add.js
export function add(a,b){
  return a + b;
};
//模塊導(dǎo)出后,在需要使用模塊的文件使用import再導(dǎo)入,就可以在這個文件內(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

以上幾個示例中,導(dǎo)入的模塊名稱都是在export的文件中設(shè)置的,也就是說用戶必須預(yù)先知道這個名稱叫什么,比如Config、add。而有的時候,用戶不想去了解名稱是什么,只是把模塊的功能拿來使用,或者想自定義名稱,這是可以使用export default 來輸出默認(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安裝了一些庫,在webpack中可以直接導(dǎo)入,示例:
import Vue from 'vue';
import $ from 'jquery';

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

首先,創(chuàng)建一個目錄,比如demo,使用NPM初始化配置:
npm init
執(zhí)行后,會有一些列選項(xiàng),可以按回車鍵快速確認(rèn),完成后會在demo目錄生產(chǎn)一個package.json的文件。
之后在本地局部安裝webpack:
npm install webpack --save-dev
--save-dev 會作為開發(fā)依賴來安裝webpack。安裝成功后,在package.json中會多一項(xiàng)配置:
"devDependencies":{
"webpack" : "^2.3.2"
}
接著需要安裝webpack-dev-server,它可以在開發(fā)環(huán)境中提供很多服務(wù),比如啟動一個服務(wù)器、熱更新、接口代理等,配置起來也很簡單。同樣,在本地局部安裝:
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就是一個.js配置文件,你的架構(gòu)好或差都體現(xiàn)在這個配置里,隨著需求的不斷出現(xiàn),工程配置也是逐漸完善的。

首先,在目錄DEMO 下創(chuàng)建一個js文件:webpack.config.js,并初始化它的內(nèi)容:
var config = {
};
module.exports = config;
這里的 module.exports = config; 相當(dāng)于 export default config;
由于目前還沒有安裝支持ES6的編譯插件,因此不能直接使用ES6的語法,否則會報(bào)錯。
然后在package.json的scripts里增加一個快速啟動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 命令時,就會執(zhí)行
webpack-dev-server --open --config webpack.config.js 命令。
其中,--config 是指向 webpack-dev-server 讀取的配置文件路徑,這里直接讀取我們在上一步創(chuàng)建的 webpack.config.js 文件。
--open 會在執(zhí)行命令時自動在瀏覽器打開頁面,默認(rèn)地址是 127.0.0.1:8080,不過IP和端口號都是可以配置的,如:

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

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

webpack配置中最重要也是必選的兩項(xiàng)是入口(Entry)和 出口(Output)。入口的作用是告訴webpack從哪里開始尋找依賴,并且編譯,出口則用來配置編譯后的文件存儲位置和文件名。
在demo目錄下新建一個空的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會從main.js文件開始工作。output中path選項(xiàng)用來存放打包后的輸出目錄,是必填項(xiàng)。publicPath指定資源文件引用的目錄,如果你的資源存放在CDN上,這里可以填CDN的網(wǎng)址。filename用于指定輸出文件的名稱。因此,這里配置的output意為打包后的文件會存儲為 demo/dist/main.js 文件,只要在html 中引入它就可以了。在demo目錄下,新建一個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í)行如下命令,就會自動在瀏覽器中打開頁面:

npm run dev

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

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

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

webpack --progress --hide-modules

這是會生成一個 demo/dist/main.js 文件,只有很少的行數(shù)。
10.上面通過配置入口(entry)和出口(Output)已經(jīng)可以啟動webpack項(xiàng)目了,不過這并不是webpack的特點(diǎn),如果它只有這些功能,根本就不用這么麻煩。webpack.config.js可以進(jìn)一步配置,來實(shí)現(xiàn)更強(qiáng)大的功能。
在webpack的世界里,每個文件都是一個模塊,比如.css、.js、.html、.jpg、.less等。對于不同的模塊,需要用不同的加載器(Loaders)來處理,而加載器就是webpack最重要的功能。通過安裝不同的加載器可以對各種后綴名的文件進(jìn)行處理,比如要寫一些CSS樣式,就要用到style-loader 和 css-loader。下面就通過NPM 來安裝它們:

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

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

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

在module對象的rule屬性中可以指定一系列的loaders,每一個loader都必須包含test和use兩個選項(xiàng)。這段配置的意思是說,當(dāng)webpack編譯過程中遇到 require()或 import 語句導(dǎo)入一個后綴名為 .css 的文件時,先將它通過 css-loader轉(zhuǎn)換,再通過style-loader 轉(zhuǎn)換,然后繼續(xù)打包。 use選項(xiàng)的值可以是數(shù)組或字符串,如果是數(shù)組,它的編譯數(shù)序就是從后往前。
在demo目錄下新建一個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 命令,可以看到頁面中的文字已經(jīng)變成紅色,并且字號也變大了。
11.可以看到,CSS是通過JavaScript動態(tài)創(chuàng)建 <style> 標(biāo)簽來寫入的,這意味著樣式代碼都已經(jīng)編譯在了main.js文件里,但在實(shí)際業(yè)務(wù)中,可能并不希望這樣做,因?yàn)轫?xiàng)目大了樣式會很多,都放在JS里太占體積,還不能做緩存。這是要用到webpack的一個重要概念——插件(Plugins)。
webpack的插件功能很強(qiáng)大,而且可以定制。這里我們使用一個 extract-text-webpack-plugin的插件來把散落在各地的css提取出來,并生成一個main.css 的文件,最終在index.html里通過<link>的形式加載它。
通過NPM安裝 extract-text-webpack-plugin 插件:
npm install extract-text-webpack-plugin --save-dev
然后在配置文件中導(dǎo)入插件,并改寫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)沒有了,通過<link>引入的main.css 文件已經(jīng)生效。
webpack 雖然概念比較新,看似復(fù)雜,但它只不過是一個js配置文件,只要搞清楚入口(Entity),出口(Output)、加載器(Loaders)和 插件(Plugins)這4個概念,使用起來就不那么困惑了。
12.單文件組件。之前,在字符串模版template選項(xiàng)里拼寫字符串DOM非常費(fèi)勁,尤其是用""換行。Vue.js是一個漸進(jìn)式的JavaScript框架,在使用webpack 構(gòu)建Vue 項(xiàng)目時,可以使用一種新的構(gòu)建模式:.vue 單文件組件。.vue 單文件組件就是一個后綴名為.vue 的文件,在webpack中使用vue-loader 就可以對.vue 格式的文件進(jìn)行處理。
一個 .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只在這個組件有效,如果不加,那么div的樣式會用到整個項(xiàng)目。<style>還可以結(jié)合CSS預(yù)編譯一起使用,比如使用 Less處理可以寫成 <style lang="less">。
13.使用.vue 文件需要先安裝 vue-loader、vue-style-loader 等加載器并做配置。因?yàn)橐褂肊S6 語法,還需要安裝babel 和 babel-loader等加載器。
使用npm 逐個安裝以下依賴:

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來支持對 .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 文件時,會對<template>、<script>、<style> 分別處理,所以在vue-loader選項(xiàng)里多了一項(xiàng)options來進(jìn)一步對不同語言進(jìn)行配置。比如在對 css進(jìn)行處理時,會先通過css-loader解析,然后把處理結(jié)果再交給 vue-style-loader 處理。當(dāng)你的技術(shù)棧多樣化時,可以給<template>、<script>、<style> 都指定不同的語言,比如<template lang="jade"> 和 <style lang="less"> , 然后配置loaders就可以了。
在demo目錄下新建一個名為.babelrc的文件,并寫入babel的配置,webpack 會依賴此配置文件來用babel 編譯ES6 代碼:

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

配置好這些后,就可以使用.vue 文件了。
每個.vue 文件就代表一個組件,組件之間可以相互依賴。
在工程目錄下新建一個app.vue的文件并寫入以下內(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 語法提示:data () { } 等同于 data:function() { }
在<template>內(nèi)寫的HTML寫法完全同html文件,webpack最終會把它編譯為Render 函數(shù)的形式。寫在<style>里的樣式,我們已經(jīng)用插件 extract-text-webpack-plugin 配置過了,最終會統(tǒng)一提取并打包在main.css 里,因?yàn)榧恿藄cope 屬性,這部分樣式只會對當(dāng)前組件app.vue 有效。
.vue 的組件是沒有名稱的,在父組件使用時可以對它自定義。寫好了組件,就可以在入口main.js 中使用它了。打開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,第一個Vue 工程就跑起來了。
打開chrome調(diào)試工具,在elements 面板可以看到,<div id="app"> 已經(jīng)被組件替換成了:

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

// 對應(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 慢的問題
可用 get命令查看registry
npm congfig get registry
原版結(jié)果為
http://registry.npmjs.org
用set命令換成阿里的鏡像就可以了
npm config set registry https://registry.npm.taobao.org
在執(zhí)行命令
npm install

接下來,在demo目錄下,再新建兩個文件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>

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

<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)入的組件都是局部注冊的,而且可以自定義名稱,其他用法和組件一致。后面會基于webpack和單文件組件展開。

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

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

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 等格式文件時,url-loader會把它們一起編譯到dist 目錄下," ?limit=1024" 是指如果這個文件小余1kb,就以base64的形式加載,不會生成一個文件。
找一張圖片,保存為 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
在安裝包時, 我們可以根據(jù)環(huán)境決定包的安裝效果. 假設(shè)我們要安裝express
1.執(zhí)行 npm i express --save則表示我想在生產(chǎn)環(huán)境中使用express, 同時, express的版本信息會被寫入package.json中的dependencies屬性中.
2.而執(zhí)行npm i express --save-dev 表示我想在開發(fā)和測試環(huán)境中使用. express的版本信息會被寫入package.json中的devDependencies屬性中.
3 --save可以簡寫為-S, --save-dev可以簡寫為-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)

三個命令:
1.查看npm服務(wù)器上所有的包版本信息
npm view babel-loader versions
2.查看該包最新的版本是哪一個
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.介紹打包上線前,先來分析webpack打包后的產(chǎn)物有哪些。
本書所介紹和使用的都是單頁面富應(yīng)用(SPA)技術(shù),這意味著最終只有一個html的文件,其余都是靜態(tài)資源。實(shí)際部署到生產(chǎn)環(huán)境時,一般會將html 掛在后端程序下,由后端路由渲染這個頁面,將頁面所有的靜態(tài)資源(css、js、image、icon、font等)單獨(dú)部署到CDN,當(dāng)然也可以和后端程序部署在一起,這樣就實(shí)現(xiàn)了前后端完全分離。
我們在webpack的output 選項(xiàng)里已經(jīng)指定了path 和 publicPath,打完包后,所有的資源都會保存在 demo/dist 目錄下。
打包會用到下面兩個依賴,使用NPM安裝:
npm install --save-dev webpack-merge
npm install --save-dev html-webpack-plugin
為了方便開發(fā)和生產(chǎn)環(huán)境的切換,我們在demo目錄下再新建一個用于生產(chǎn)環(huán)境的配置文件 webpack.prod.config.js。
編譯打包,直接執(zhí)行webpack 命令就可以。在package.json中,再加入一個build的快捷腳本用來打包:

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

先來看一下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 模塊就是用于合并兩個webpack 的配置文件,所以prod 的配置是在webpack.config.js 基礎(chǔ)上擴(kuò)展的。靜態(tài)資源在大部分場景下都有緩存(304),更新上線后一般都希望用戶能及時地看到內(nèi)容,所以給打包后的css和js文件的名稱都加了20位的hash值。這樣文件名就唯一了(比如 main.b3dd20e2dae9d76af86b.js),只要不對html文件設(shè)置緩存,上線后立即就可以加載最新的靜態(tài)資源。
html-webpack-plugin 是用來生成html 文件的,它通過template 選項(xiàng)來讀取指定的模板 index.ejs,然后輸出到filename 指定的目錄,也就是demo/index_prod.html。模板 index.ejs 動態(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,等待一會就會完成打包,成功后在demo下會生成一個dist的目錄,里面就是打包完的所有靜態(tài)資源。

ejs 是一個JavaScript 模板庫,用來從JSON 數(shù)據(jù)中生成HTML 字符串,常用于 Node.js。

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

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容