Tracy 小筆記 Vue - webpack 打包

2021-06-06 07:00:01

webpack

針對 JS 的模組化打包工具

檢視當前版本 webpack --version

安裝

webpack 的執行需要依賴 node 環境,因此需要先行安裝 node 版本要大於 8.9
node 環境為了可以正常的執行很多程式碼,會包含各種依賴的包 所以安裝node 之後會自動會安裝 npm (node package manager) 用來管理 node 上面的各種包

全域性安裝 3.6.0, 因為 vue cil 2 依賴該版本: npm install webpack@3.6.0 -g
區域性安裝 : cd 到目錄 npm install webpack@3.6.0 --save--dev

為何全域性安裝後還要區域性安裝呢:

  • 在終端執行 webpack 命令時,使用的都是全域性安裝的 webpack. 如 cmd 終端或者編輯器自帶的終端。
  • 在 package.json 檔案中定義了 script 時,其中包含了 webpack 命令的話,那麼它優先呼叫的就是區域性的 webpack. 區域性沒有才會呼叫全域性的。 這樣在很多人一起做專案的時候只需要用區域性的打包,每個人的全域性的不一樣也不要緊。
  • 一個專案往往是特定版本的 webpack, 都使用全域性的話 會導致打包出現問題

打包

src: 原始碼資料夾 (裡面有 js; hbs; cjs; sass; image; json)
dist: 打包資料夾 (distribution 釋出)(裡面有:css; js; image)

一般 src 資料夾中會由一個入口 js, main.js/index.js
這個js 會呼叫專案裡的各種其他 js. 我們會把所有的 js 打包成一個 bundle.js
cd 到資料夾,webpack 打包命令: webpack ./src/main.js ./dist/bundle.js (這裡雖然cd 到資料夾了,其實用的還是全域性 webpack)

webpack.config.js 檔案設定

  • 可以把上面的"webpack 打包命令"直接簡寫成 webpack 然後在該組態檔中設定一些東西來實現 webpack ./src/main.js ./dist/bundle.js
  • const path = require('path'); //動態獲取絕對路徑需要引入的包(webpack 自帶)
    
    module.exports = {
      entry : "./src/main.js", //想要打包的主 js 檔案, 專案的入口檔案
      output: {
         path: path.resolve(__dirname, 'dist'), //動態的獲取絕對路徑 __dirname 是 npm 的全域性變數
         filename: 'bundle.js', //打包之後生成的檔案
         publicPath: 'dist/' //檔案(如圖片)打包之後傳送到的資料夾
      },
      module: {
        rules: [
         //設定 各種 loader
        ]
      }
    }
    
  • 執行的時候 直接 cd 到資料夾 執行命令 webpack 即可呼叫區域性 webpack 進行打包工作

package.json 設定

  • 它是 npm init 初始化生成的檔案
  • {
      "name": "tracytestvue", //專案名稱
      "version": "1.0.0", //專案版本
      "description": "Tracy test vue project", //專案描述
      "main": "webpack.config.js", //以後講
      "dependencies": { //專案開發時依賴 這裡不需要我們自己編輯 npm insert ... 之後會自動新增到這裡
        "webpack": "^3.6.0" //說明專案安裝了本地 webpack
      },
      "devDependencies": {//專案執行時依賴
      "webpack-bundle-analyzer": "^4.4.0", //分析哪個 js 檔案大,影響頁面載入速度的
    
      },
      "scripts": { //npm run ... 的對映
        "build": "webpack"// npm run build 時候執行 webpack (這裡會呼叫區域性的 webpack),
        "test":"node .build/copy.js" //node 可以拋開瀏覽器直接執行js 檔案,因為伺服器沒有瀏覽器, node 的使用使得 js 檔案可以成為伺服器程式碼
      },
      "author": "Tracy", //作者
      "license": "ISC"//開源專案的時候才會用的設
    }
    
  • 這個檔案裡是不能寫註釋的,寫註釋後就不能正確執行 npm run build 了

loader 的使用

  • webpack 本身的功能只能支援 js 模組化的打包。 針對於其他檔案型別的模組化打包,我們需要給 webpack 下載不同的 loader.
  • loader 涉及的打包領域有: ES6 轉 ES5, TypesScript 轉換成 ES5, 將 scss/less 轉成 css, 將 jsx/vue 檔案轉成 js 檔案
  • loader 的使用過程:
    步驟1: 通過 npm 安裝對應的 loader
    步驟2: 在 webpack.config.js 中的 module 關鍵字下面進行設定
  • loader 官網 (org 結尾的網站一般都是非盈利性質的)
    loader 中文翻譯
  • Demo 1 : 將 css 打包進入 bundle.js 檔案中
    • 入口 main.js 中寫入: import style from './css/common.css'
    • npm install style-loader --save-dev
      npm install --save-dev css-loader
    • webpack.config.js 設定:
      module: {
          rules: [{
            test: /\.css$/,
            use: [
              { loader: "style-loader" }, { loader: "css-loader" }
            ]
          }]
        }
    • 注意: use 陣列後面有多個 loader. webpack 是從右向左來讀取的, 所以要先寫 style-loader 再寫 css-loader
      css-loader 只負責將 css 檔案進行載入,但是並不會將檔案加入到 DOM 中,因此頁面不會有樣式
      style-loader 負責將樣式加入到 DOM 中, 此時頁面才開始有樣式
    • Tips: 如果打包出錯,就檢視 package.json 檔案 css-loader 和 js-loader 的版本 是不是太高了
      在 package.json 檔案手動更改版本為 "css-loader": "^3.3.0", "style-loader": "^1.0.0"
      之後執行 npm install 會自動新增我們手動修改的版本
      再次打包之後錯誤消失
  • 不同的 loader 都需要寫在 rules 中, rules 是一個陣列。
  • Demo 2 : 打包 less, scss, sass 的樣式檔案
    • main.js 引入 less : import less from './css/demo.less'
    • npm install --save-dev less-loader less
    • webpack.config.js 設定:
      {
        test: /\.less$/,
        use: [{ loader: "style-loader" }, { loader: "css-loader" }, { loader: "less-loader" }]
      }
    • less-loader的時候經常會因為版本過高報錯, 在 package.json 檔案手動更改版本為 4.1.0 之後執行 npm install
  • Demo 3: 打包 image 為 Base64 字串格式 url-loader 功能類似於 file-loader,但是在檔案大小(單位 byte)低於指定的限制時,可以返回一個 DataURL。
    • css 檔案中引入 image: background-image: url('../images/view.png');
    • npm install --save-dev url-loader
    • {
        test: /\.(png|jpg|gif|jpeg)$/, //這裡我們自己加上 jpeg
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192 //當載入的圖片小於 limit 的 8kb 的時候會將圖片編譯成 base64 字串形式 
              //當圖片大於 8kb 的時候需要再下載 file-loader, 這裡就不用額外設定什麼了
              name: 'images/[name].[hash:8].[ext]' //圖片大於 limit file-loader 生成的名字
            }
          }
        ]
      }
    • 圖片小於 8kb 打包之後css 檔案會變成類似於: background-image:url(data:image/png;base64,iVBORw0KGgoAAAAN...=)
    • 當圖片大於 設定的 limit 的 8kb 後會報錯, 此時我們需要再設定 npm install --save-dev file-loader
      file-loader : 將檔案傳送到輸出資料夾,並返回(相對)URL
    • webpacl.config 的 output 中需要設定圖片要傳送過去的資料夾 publicPath: 'dist/'
    • 其他不用再額外設定了,直接 npm run build 即可
      版本過高報錯, 在 package.json 檔案手動更改版本為 "file-loader": "^4.0.0"
    • 檔案會被改名,成為 32位元的 hash 雜湊值。傳送到 publicPath 的資料夾
      但是真實開發中,我們對打包的檔案名字是有一定的要求的,此時就要在 option 新增如下選項
      name: 'images/[name].[hash:8].[ext]'
      • images : 檔案要打包的資料夾
      • [name] : 獲取圖片原來的名字
      • [hash:8]: 放置圖片名字重複,依然使用 hash, 保留 8位元
      • [ext]: 使用原來檔案的拓展名
  • Demo 4: ES6 轉 ES5
    • npm
    • npm install babel-loader babel-core babel-preset-es2015
      這裡先不要按照官網的用 babel-preset-env
    • {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/, //排除 node_modules 和 bower_components 裡的檔案
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['es2015']
          }
        }
      }
    • 如果用官網的 babel-preset-env 打包報錯後,需要在 webpack.config.js 同級目錄建立檔案" .babelrc." 然後再進行具體的設定
    • 你必須執行 npm install babel-plugin-transform-runtime --save-dev 來把它包含到你的專案中,也要使用 npm install babel-runtime --save-dev 把 babel-runtime 安裝為一個依賴。
  • Demo 5: 打包 .vue 檔案
    • npm install vue-loader vue-template-compiler --save-dev
    • webpack.config.js 設定:
      module: {
          rules: [{
            test: /\.vue$/,
            use: [
              { loader: "vue-loader"}
            ]
          }]
        }
    • 此時會報錯: vue-loader was used without the corresponding plugin.
      因為 vue loader 版本過高, 可以改成 ^13.0.0 (這個^的意思是會安裝 13到14之間的一個合適的版本)
      重新 npm install
    • 引入 vue 檔案想從 import App from './vue/App.vue' 變成 import App from './vue/App'
      去掉字尾名: 在 webpack.config.js 檔案中的 resolve 中設定
      resolve: {
        extensions:['.js', '.css', '.vue'],
      } 
                      

webpack 中設定 Vue

  • 打包 .vue 檔案
  • npm install vue --save (這裡不用 --dev 了,因為 vue 不僅是開發時依賴,而且也是執行時依賴)
    預設是安裝最新的版本
  • 安裝好之後直接引入 import Vue from 'vue';
  • 使用 vue code 進行開發 並打包,此時瀏覽器 console 會報錯
    [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.
  • Vue 不同構件版本: Vue 在 import 的時候會參照兩種檔案
    • runtime-only: (預設參照) 程式碼中不可以有任何的 template
    • runtime-compiler: 程式碼中可以有 template, 因為有 compiler 用於編輯 template
    • template 也就是元件,我們的程式碼裡有根元件,它也是一個元件,所以用 runtime-only 會報錯了
  • 解決 runtime-only 報錯方案 :
    修改 webpack.config.js, 新增如下屬性:
    resolve: {
      alias: {
        'vue$': 'vue/dist/vue.esm.js'
      }
    }

    新增了之後, 在我們 import vue 的時候,就不會預設醫用 runtime-only 了, 而是參照 runtime-compiler
  • vue 終極解決方案
    • index.html 檔案中
      <div id="app"></div>
      <script src="./dist/bundle.js"></script>
    • main.js 檔案
      import style from './css/common.css'
      import less from './css/demo.less'
      
      // vue
      import Vue from 'vue';
      import App from './vue/App'
      
      new Vue({
        el: '#app',
        template: '<App />',
        components: { App }
      });

       

    • App.vue 檔案: 正常 vue code

plugin 的使用

  • plugin 是外掛,對現有框架的功能進行擴充套件
  • 使用步驟
    1. 安裝: npm *** (某些外掛webpack 已經內建因此才不用安裝)
    2. 設定: webpack.config.js 中的 plugins :[] 中設定外掛
  • Demo: 新增版權宣告
    • 安裝: 它是 webpack 內建外掛所以不用再次安裝了
    • 設定 const webpack = require ('webpack');
      plugins :[ new webpack.BannerPlugin('最終版權歸 Tracy 所有') ]
  • 打包 html
    目前的 index.html 檔案還在 dist 資料夾外面,釋出的時候還不是很方便。
    需要將 html 檔案打包到 dist 資料夾中釋出的時候就拽這個資料夾即可
    • 這個外掛為我們做的: 自動生成一個index.html檔案(可以指定模板來生成)
      並且將打包好的 js 檔案自動通過 script 標籤插入到 index.html 的 body 中
    • 安裝: npm install html-webpack-plugin --save--div
    • 設定: const htmlWebpackPlugin = require('html-webpack-plugin');
      new htmlWebpackPlugin({template: 'index.html'})
    • 這裡的 template 表示根據什麼模板來生成 html, 我們目前的 html 是和 webpack.config.js 在同一目錄,因此直接寫的 index.html 就能找到對應的檔案
      另外我們需要刪除之前在 out put 之中新增的 publicPath 屬性,否則插入的js路徑會有問題
    • error : Cannot read property 'make' of undefined
      方法將"html-webpack-plugin"版本由 "^4.2.0"改為 "^3.2.0",
    • 原來 index.html body 中只寫 <div id="app"></div> 即可,引入 js 什麼的都不用寫了
  • 壓縮 JS
    • 安裝: npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
    • 設定: const uglifyjsPlugin = request('uglifyjs-webpack-plugin');
      new uglifyjsPlugin()
    • 此時會發現打包報錯:報錯是因為最新版的uglifyjs-webpack-plugin外掛已經不支援es6語法, 所以已經不適合用這個外掛了

搭建本地伺服器

  • 可以實現瀏覽器自動重新整理我們改動之後的效果,每次改動後專案會自動打包到記憶體中
  • 安裝: npm install --save-dev webpack-dev-server@2.9.1
  • 在 webpack.config.js 中設定
    devServer:{ contentBase:'./dist', //為哪一個資料夾提供本地 server 服務 port:埠號, //不設定的話就是8080 inline: true, //頁面實時重新整理 historyApiFallbacl: 在SPA(單頁應用)中,依賴 htmk5 的 history 模式,以後細講 }
  • 在 package.json 中的 "scripts" 裡設定 "dev": "webpack-dev-server --open" (這裡的open 是指執行時候直接開啟瀏覽器)
  • 啟動專案的時候 npm run dev

webpack 組態檔 config.js 的分離

  • 如果把所有的設定都放倒一個 webpack.config.js 檔案中,那麼在設定很多的時候,是不太合適的.
    有些東西是隻在測試環境的時候才需要設定的,比如說「搭建本地伺服器」
    有些東西是隻在部署環境的時候才需要設定的,比如說醜化js 和 版權管理等
  • 因此我們要把組態檔至少分成三個:
  • base.config.js: 測試和部署環境都會用到的設定
  • dev.config.js: 測試環境設定
  • prod.config.js: 部署環境設定
  • 三個檔案都放倒 build 資料夾中
    base.config.js 中的設定就要改了,因為資料夾換了: path: path.resolve(__dirname, '../dist'),
  • 安裝 npm install webpack-merge --save-dev 用於在 dev.config.js 檔案中將它自己和 base.config.js 合併,執行的時候執行一個 dev.config.js 即可
    在 dev.config.js 和 prod.config.js 中分別設定 :
    const webpackMerge = require('webpack-merge');
    const baseConfig = require('./base.config');
    module.exports = webpackMerge.merge(baseConfig, {裡面放 dev.config.js 或者 prod.config.js 裡的 code})
  • 刪除 webpack.config.js
    在 package.json 檔案的 "script"中加上 --config ./build/###.config.js 用於覆蓋原來預設的 webpack.config.js 檔案的操作
    "build": "webpack --config ./build/prod.config.js",
    "dev": "webpack-dev-server --open --config ./build/dev.config.js"