4.Webpack詳解

webpack基礎

認識webpack

webpack是一個現代的JavaScript應用的靜態模塊打包工具。
webpack.png
涉及到兩個概念:模塊打包css

模塊

經過模塊化開發完成項目後,還須要處理模塊間的各類依賴,而且將其進行整合打包。而webpack其中一個核心就是讓咱們可能進行模塊化開發,而且會幫助咱們處理模塊間的依賴關係。並且不只僅是JavaScript文件,咱們的CSS、圖片、json文件等等在webpack中均可以被當作模塊來使用。這就是webpack中模塊化的概念。html

打包

就是將webpack中的各類資源模塊進行打包合併成一個或多個包(Bundle)。而且在打包的過程當中,還能夠對資源進行處理,好比壓縮圖片,將scss轉成css,將ES6語法轉成ES5語法,將TypeScript轉成JavaScript等等操做。前端

但打包的操做彷佛grunt/gulp也能夠幫助咱們完成,它們有什麼不一樣呢?vue

和grunt/gulp的對比

grunt/gulp的核心是Task
咱們能夠配置一系列的task,而且定義task要處理的事務(例如ES六、ts轉化,圖片壓縮,scss轉成css)。以後讓grunt/gulp來依次執行這些task,並且讓整個流程自動化。因此grunt/gulp也被稱爲前端自動化任務管理工具。node

來看一個gulp的task:下面的task就是將src下面的全部js文件轉成ES5的語法。而且最終輸出到dist文件夾中。webpack

const gu1p = requireC('gulp');
const babe1 = require('gu1p-babe1');
gulp.task('js',()=>
    gulp.src('src/*.js')
        .pipe(babe1({
            presets: ['es2015']
        }))
        .pipe(gulp. dest('dist'))
);

何時用grunt/gulp呢?
若是你的工程模塊依賴很是簡單,甚至是沒有用到模塊化的概念。只須要進行簡單的合併、壓縮,就使用grunt/gulp便可。可是若是整個項目使用了模塊化管理,並且相互依賴很是強,咱們就可使用更增強大的webpack了。
因此,grunt/gulp和webpack有什麼不一樣呢?web

  • grunt/gulp更增強調的是前端流程的自動化,模塊化不是它的核心。
  • webpack更增強調模塊化開發管理,而文件壓縮合並、預處理等功能,是他附帶的功能。

webpack的安裝

安裝webpack首先須要安裝Node.js,Node.js自帶了軟件包管理工具npm。express

cnpm install webpack --save-dev
//--save-dev是開發時依賴,項目打包後不須要繼續使用的。

在終端直接執行webpack命令,使用的全局安裝的webpack。當在package.json中定義了scripts時,其中包含了webpack命令,那麼使用的是局部webpack。npm

webpack的起步

文件和文件夾解析:
dist文件夾:用於存放以後打包的文件
src文件夾:用於存放咱們寫的源文件
-----main.js項目的入口 文件。具體內容查看下面詳情。
index.html:瀏覽器打開展現的首頁html
package.json:經過npm init生成的,npm包管理的文件(暫時沒有用上,後面纔會用上)json

js文件的打包

webpack src/main.js dist/bundle.js

使用打包後的文件
打包後會在dist文件下,生成一個bundle.js文件。bundle.js文件,是webpack處理了項目直接文件依賴後生成的一個js文件,咱們只須要將這個js文件在index.html中引入便可

webpack的配置

入口和出口

若是每次使用webpack的命令都須要寫上入口和出口做爲參數,有一種方法能夠將這兩個參數寫到配置中,在運行時,直接讀取。

建立一個webpack.config.js文件
const path = require('path')
module.exports = {
    //入口:能夠是字符串/數組/對象,這裏咱們入口只有一個,因此寫一個字符串便可
    entry:'./src/main.js' ,
    //出口:一般是一個對象,裏面至少包含兩個重要屬性,path 和filename
    output:{
        path: path. resolve(__dirname, 'dist'), //注意: path一般是一 個絕對路徑
        filename: 'bundle.js'
    }
}
局部安裝webpack

由於一個項目每每依賴特定的webpack版本,全局的版本可能很這個項目的webpack版本不一致,導出打包出現問題。因此一般一個項目,都有本身局部的webpack。

//安裝指定本身須要的版本
cnpm install webpack@3.6.0 --save-dev
//啓動webpack打包
node_modules/.bin/webpack
package.json中定義啓動

咱們能夠在package.json的scripts中定義本身的執行腳本。

{
    "name": "meetwebpack",
    "version": "1.0.0",
    "description":"",
    "main": 'index.js',
    "scripts": {
        "build": "'webpack"
    },
    "author":"",
    "license":"ISC",
    "devDependencies": {
        "webpack": "^3. 6. 0"
    }
}

package.json中的scripts的腳本在執行時,會按照必定的順序尋找命令對應的位置。
首先,會尋找本地的node_modules/.bin路徑中對應的命令。若是沒有找到,會去全局的環境變量中尋找。

//執行build指令
cnpm run build

loader的使用

什麼是loader?
loader是webpack中一個很是核心的概念。在開發中咱們不只僅有基本的js代碼處理,咱們也須要加載css、圖片,也包括一些高級的將ES6轉成ES5代碼,將TypeScript轉成ES5代碼,將scss、less轉成css,將.jsx、.vue文件轉成js文件等等。對於webpack自己的能力來講,對於這些轉化是不支持的。此時須要給webpack擴展對應的loader。
loader使用過程:
步驟一:經過npm安裝須要使用的loader
步驟二:在webpack.config.js中的modules關鍵字下進行配置
大部分loader咱們均可以在webpack的官網中找到,而且學習對應的用法。loader 的執行順序是從下到上,從右到左。

css文件處理

須要用到兩個loader:css-loaderstyle-loadercss-loader負責加載css文件;style-loader負責將css具體樣式嵌入到文檔中。
安裝

cnpm install --save-dev css-loader style-loader

webpack.config.js中配置

const path = require('path');

module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module:{
        rules:[
            { 
                test:/\.css$/, 
                use:['style-loader','css-loader'], 
            }
        ]
    },

}

由於webpack在讀取使用的loader的過程當中,是按照從右向左的順序讀取的。因此style-loader須要放在css-loader的前面。

less/scss文件處理

須要安裝less 和 less-loader

rules: [{
            test: /\.less$/,
            use: [{
                loader: "style-loader" // creates style nodes from JS strings
            }, {
                loader: "css-loader" // translates CSS into CommonJS
            }, {
                loader: "less-loader" // compiles Less to CSS
            }]
        }]

圖片文件處理

url-loaderfile-loader
當加載的圖片, 小於limit時, 會將圖片編譯成base64字符串形式.
當加載的圖片, 大於limit時, 須要使用file-loader模塊進行加載.
修改文件名稱
當圖片大於limit時,使用file-loader默認會將該圖片打包從新命名爲32位的hash值放到dist文件夾下。

{
    test: /\.(png|jpg|gif|jpeg)$/,
    use: [
      {
        loader: 'url-loader',
        options: {
          // 當加載的圖片, 小於limit時, 會將圖片編譯成base64字符串形式.
          // 當加載的圖片, 大於limit時, 須要使用file-loader模塊進行加載.
          limit: 13000,
          // [ext]:表示原始文件名的後綴。[name]:表示原始文件名。[hash:8]:爲了防止圖片名稱衝突,依然使用hash,可是咱們只保留8位
          name: 'img/[name].[hash:8].[ext]'
        },
      }
    ]
},

咱們發現圖片並無顯示出來,這是由於圖片使用的路徑不正確。默認狀況下,webpack會將生成的路徑直接返回給使用者可是,咱們整個程序是打包在dist文件夾下的,因此這裏咱們須要在路徑下再添加一個dist/

output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: 'dist/'
},

babel 的使用

若是但願將ES6的語法轉成ES5,那麼就須要使用babel。而在webpack中,咱們直接使用babel對應的loader就能夠了。

npm install --save-dev babel-loader@7 babel-core babel-preset-es2015

配置webpack.config.js文件

{
    test: /\.js$/,
    // exclude: 排除
    // include: 包含
    exclude: /(node_modules|bower_components)/,
    use: {
      loader: 'babel-loader',
      options: {
        presets: ['es2015']
      }
    }
}

plugin的使用

plugin是插件的意思,一般是用於對某個現有的架構進行擴展。webpack中的插件,就是對webpack現有功能的各類擴展,好比打包優化,文件壓縮等等。

loader和plugin區別

loader主要用於轉換某些類型的模塊,它是一個轉換器
plugin是插件,它是對webpack自己的擴展,是一個擴展器

plugin的使用過程:

步驟一:經過npm安裝須要使用的plugins(某些webpack已經內置的插件不須要安裝)
步驟二:在webpack.config.js中的plugins中配置插件。

添加版權的Plugin

BannerPlugin,屬於webpack自帶的插件。

const path = require('path')
const webpack = require('webpack')

module.exports = {
  ...
  plugins: [
      new webpack.BannerPlugin('最終版權歸aaa全部'),
  ],
}
打包html的plugin

在真實發布項目時,須要將index.html文件打包到dist文件夾中,這個時候就可使用 HtmlWebpackPlugin插件。HtmlWebpackPlugin插件能夠爲咱們作這些事情:自動生成一個index.html文件(能夠指定模板來生成)將打包的js文件,自動經過script標籤插入到body中。

npm install html-webpack-plugin --save-dev
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  ...
  plugins: [
      new HtmlWebpackPlugin({
        template: 'index.html'//指定生成Html文件時使用的模板。
      }),
  ],
}

另外,咱們須要刪除以前在output中添加的publicPath屬性,不然插入的script標籤中的src可能會有問題。

CleanWebpackPlugin

CleanWebpackPlugin 會在打包以前刪除指定目錄下的內容。

npm install clean-webpack-plugin -D

webpack.config.js

const {CleanWebpackPlugin} = require('clean-webpack-plugin'); //注意加{}
module.exports = {
    ...
    plugins:[
        new HtmlWebpackPlugin({
            template: 'src/index.html'
        }), 
        new CleanWebpackPlugin() //不能加參數。
    ],
}

搭建本地服務器

webpack提供了一個可選的本地開發服務器,這個本地服務器基於node.js搭建,內部使用express框架,能夠實現咱們想要的讓瀏覽器自動刷新顯示咱們修改後的結果。

npm install --save-dev webpack-dev-server@2.9.1

devserver也是做爲webpack中的一個選項,選項自己能夠設置以下屬性:

`contentBase`:爲哪個文件夾提供本地服務,默認是根文件夾,咱們這裏要填寫./dist
`port`:端口號
`inline`:頁面實時刷新
`historyApiFallback`:在SPA頁面中,依賴HTML5的history模式
devServer: {
    contentBase: './dist',
    inline: true
}

能夠再配置另一個scripts:--open參數表示直接打開瀏覽器

"scripts": {
    "build": "webpack",
    "dev": "webpack-dev-server --open"
},

webpack中配置Vue

el和template區別

在前面的Vue實例中,咱們定義了el屬性,用於和index.html中的#app進行綁定,讓Vue實例以後能夠管理它其中的內容。
這裏,咱們能夠將div元素中的{{message}}內容刪掉,只保留一個基本的id爲div的元素
可是若是我依然但願在其中顯示{{message}}的內容,應該怎麼處理呢?
咱們能夠再定義一個template屬性,代碼以下:

new Vue({
    el: '#app',
    template: '<div id="app">{{message}}</div>',
    data: {
        message:'coderwhy'
    }
})

el和template模板的關係是什麼呢?
el用於指定Vue要管理的DOM,能夠幫助解析其中的指令、事件監聽等等。
而若是Vue實例中同時指定了template,那麼template模板的內容會替換掉掛載的對應el的模板。這樣作以後咱們就不須要在之後的開發中再次操做index.html,只須要在template中寫入對應的標籤便可

稍後會將template模板中的內容進行抽離。會分紅三部分書寫:templatescriptstyle,結構變得很是清晰。

.vue文件封裝處理

main.js

//使用Vue進行開發
import Vue from 'vue'
import App from './vue/App.vue'

new Vue({
  el: '#app',
  template: '<App/>',
  components: {
    App
  }
})

vue-->App.vue

<template>
  <div>
    <h2 class="title">{{message}}</h2>
    <h2>{{name}}</h2>
  </div>
</template>

<script>
  export default {
    name: "App",
    data() {
      return {
        message: 'Hello Webpack',
        name: '張三'
      }
    },
  }
</script>

<style scoped>
  .title {
    color: green;
  }
</style>

安裝vue、vue-loader 和 vue-template-compiler 進行處理。

npm install vue-loader vue-template-compiler --save-dev
cnpm install vue --save
module: {
    rules: [
      {
        test: /\.vue$/,
        use: ['vue-loader']
      }
    ]
},
//解決runtime-only版本的Vue報錯
resolve: {
    // alias: 別名
    extensions: ['.js', '.css', '.vue'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
}
相關文章
相關標籤/搜索