整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          使用Jenkins一鍵打包部署SpringBoot應(yīng)

          使用Jenkins一鍵打包部署SpringBoot應(yīng)用,就是這么6

          任何簡(jiǎn)單操作的背后,都有一套相當(dāng)復(fù)雜的機(jī)制。本文將以SpringBoot應(yīng)用的在Docker環(huán)境下的打包部署為例,詳細(xì)講解如何使用Jenkins一鍵打包部署SpringBoot應(yīng)用。

          Jenkins簡(jiǎn)介

          Jenkins是開(kāi)源CI&CD軟件領(lǐng)導(dǎo)者,提供超過(guò)1000個(gè)插件來(lái)支持構(gòu)建、部署、自動(dòng)化,滿足任何項(xiàng)目的需要。我們可以用Jenkins來(lái)構(gòu)建和部署我們的項(xiàng)目,比如說(shuō)從我們的代碼倉(cāng)庫(kù)獲取代碼,然后將我們的代碼打包成可執(zhí)行的文件,之后通過(guò)遠(yuǎn)程的ssh工具執(zhí)行腳本來(lái)運(yùn)行我們的項(xiàng)目。

          Jenkins的安裝及配置

          Docker環(huán)境下的安裝

          • 下載Jenkins的Docker鏡像:
          docker pull jenkins/jenkins:lts
          復(fù)制代碼
          • 在Docker容器中運(yùn)行Jenkins:
          docker run -p 8080:8080 -p 50000:5000 --name jenkins \
          -u root \
          -v /mydata/jenkins_home:/var/jenkins_home \
          -d jenkins/jenkins:lts
          復(fù)制代碼

          Jenkins的配置

          • 運(yùn)行成功后訪問(wèn)該地址登錄Jenkins,第一次登錄需要輸入管理員密碼:http://192.168.6.132:8080/



          • 使用管理員密碼進(jìn)行登錄,可以使用以下命令從容器啟動(dòng)日志中獲取管理密碼:
          docker logs jenkins
          復(fù)制代碼
          • 從日志中獲取管理員密碼:



          • 選擇安裝插件方式,這里我們直接安裝推薦的插件:



          • 進(jìn)入插件安裝界面,聯(lián)網(wǎng)等待插件安裝:



          • 安裝完成后,創(chuàng)建管理員賬號(hào):



          • 進(jìn)行實(shí)例配置,配置Jenkins的URL:



          • 點(diǎn)擊系統(tǒng)管理->插件管理,進(jìn)行一些自定義的插件安裝:



          • 確保以下插件被正確安裝: 根據(jù)角色管理權(quán)限的插件:Role-based Authorization Strategy 遠(yuǎn)程使用ssh的插件:SSH plugin
          • 通過(guò)系統(tǒng)管理->全局工具配置來(lái)進(jìn)行全局工具的配置,比如maven的配置:



          • 新增maven的安裝配置:



          • 在系統(tǒng)管理->系統(tǒng)配置中添加全局ssh的配置,這樣Jenkins使用ssh就可以執(zhí)行遠(yuǎn)程的linux腳本了:



          角色權(quán)限管理

          我們可以使用Jenkins的角色管理插件來(lái)管理Jenkins的用戶,比如我們可以給管理員賦予所有權(quán)限,運(yùn)維人員賦予執(zhí)行任務(wù)的相關(guān)權(quán)限,其他人員只賦予查看權(quán)限。

          • 在系統(tǒng)管理->全局安全配置中啟用基于角色的權(quán)限管理:



          • 進(jìn)入系統(tǒng)管理->Manage and Assign Roles界面:



          • 添加角色與權(quán)限的關(guān)系:



          • 給用戶分配角色:



          打包部署SpringBoot應(yīng)用

          這里我們使用mall-learning項(xiàng)目中的mall-tiny-jenkins模塊代碼來(lái)演示下如何使Jenkins一鍵打包部署SpringBoot應(yīng)用。

          將代碼上傳到Git倉(cāng)庫(kù)

          • 首先我們需要安裝Gitlab(當(dāng)然你也可以使用Github或者Gitee),然后將mall-tiny-jenkins中的代碼上傳到Gitlab中去,Gitlab的使用請(qǐng)參考:10分鐘搭建自己的Git倉(cāng)庫(kù)
          • mall-tiny-jenkins項(xiàng)目源碼地址:github.com/macrozheng/…
          • 上傳完成后Gitlab中的展示效果如下:



          • 有一點(diǎn)需要注意,要將pom.xml中的dockerHost地址改成你自己的Docker鏡像倉(cāng)庫(kù)地址:



          執(zhí)行腳本準(zhǔn)備

          • 將mall-tiny-jenkins.sh腳本文件上傳到/mydata/sh目錄下,腳本內(nèi)容如下:
          #!/usr/bin/env bash
          app_name='mall-tiny-jenkins'
          docker stop ${app_name}
          echo '----stop container----'
          docker rm ${app_name}
          echo '----rm container----'
          docker run -p 8088:8088 --name ${app_name} \
          --link mysql:db \
          -v /etc/localtime:/etc/localtime \
          -v /mydata/app/${app_name}/logs:/var/logs \
          -d mall-tiny/${app_name}:1.0-SNAPSHOT
          echo '----start container----'
          復(fù)制代碼
          • 給.sh腳本添加可執(zhí)行權(quán)限:
          chmod +x ./mall-tiny-jenkins.sh  
          復(fù)制代碼
          • windows下的.sh腳本上傳到linux上使用,需要修改文件格式,否則會(huì)因?yàn)橛刑厥飧袷酱嬖诙鵁o(wú)法執(zhí)行:
          #使用vim編輯器來(lái)修改
          vi mall-tiny-jenkins.sh
          # 查看文件格式,windows上傳上來(lái)的默認(rèn)為dos
          :set ff 
          #修改文件格式為unix
          :set ff=unix 
          #保存并退出
          :wq
          復(fù)制代碼
          • 執(zhí)行.sh腳本,測(cè)試使用,可以不執(zhí)行:
          ./mall-tiny-jenkins.sh
          復(fù)制代碼

          在Jenkins中創(chuàng)建執(zhí)行任務(wù)

          • 首先我們需要新建一個(gè)任務(wù):

          • 設(shè)置任務(wù)名稱后選擇構(gòu)建一個(gè)自由風(fēng)格的軟件項(xiàng)目:



          • 然后在源碼管理中添加我們的git倉(cāng)庫(kù)地址:http://192.168.6.132:1080/macrozheng/mall-tiny-jenkins



          • 此時(shí)需要添加一個(gè)憑據(jù),也就是我們git倉(cāng)庫(kù)的賬號(hào)密碼:



          • 填寫完成后選擇該憑據(jù),就可以正常連接git倉(cāng)庫(kù)了;



          • 之后我們需要添加一個(gè)構(gòu)建,選擇調(diào)用頂層maven目標(biāo),該構(gòu)建主要用于把我們的源碼打包成Docker鏡像并上傳到我們的Docker鏡像倉(cāng)庫(kù)去:



          • 選擇我們的maven版本,然后設(shè)置maven命令和指定pom文件位置:



          • 之后添加一個(gè)執(zhí)行遠(yuǎn)程shell腳本的構(gòu)建,用于在我們的鏡像打包完成后執(zhí)行啟動(dòng)Docker容器的.sh腳本:



          • 需要設(shè)置執(zhí)行的shell命令如下:/mydata/sh/mall-tiny-jenkins.sh



          • 之后點(diǎn)擊保存操作,我們的任務(wù)就創(chuàng)建完成了,在任務(wù)列表中我們可以點(diǎn)擊運(yùn)行來(lái)執(zhí)行該任務(wù);



          • 我們可以通過(guò)控制臺(tái)輸出來(lái)查看整個(gè)任務(wù)的執(zhí)行過(guò)程:



          • 運(yùn)行成功后,訪問(wèn)該地址即可查看API文檔:http://192.168.6.132:8088/swagger-ui.html



          作者:MacroZheng
          鏈接:https://juejin.im/post/5df780d3e51d4557ff140b30

          語(yǔ)

          在最近的項(xiàng)目開(kāi)發(fā)中,涉及到了多頁(yè)面的 webpack 打包,以下是我項(xiàng)目過(guò)程中的一些踩坑總結(jié)。

          前言

          項(xiàng)目使用了 vue 作為框架來(lái)開(kāi)發(fā)前端頁(yè)面,其中需要開(kāi)發(fā)多個(gè)前端頁(yè)面,包括有登錄、進(jìn)游戲、充值等等。作為vue最佳的打包工具—— webpack,需要將各個(gè)頁(yè)面分別打包到不同模板目錄里。

          但默認(rèn)的 vue 項(xiàng)目框架是單頁(yè)面應(yīng)用的,并不能達(dá)到項(xiàng)目開(kāi)發(fā)的目的。這就需要調(diào)整 webpack 的配置來(lái)實(shí)現(xiàn)多頁(yè)面的發(fā)布處理。

          以下是目錄結(jié)構(gòu):

          project
          ├───bin
          │   └───vb.js
          ├───build
          │   │   dev.js
          │   │   release.js
          │   │   webpack.config.base.js
          │   │   webpack.config.build.js
          │   └───webpack.config.dev.js
          │   README.md
          │   package.json
          └───src
              ├───components
              │   │   count.vue
              │   │   dialog.vue
              │   │   errortips.vue
              │   └───...
              ├───game
              │   │   game.htm
              │   │   game.js
              │   └───game.vue
              ├───login
              │   │   login.htm
              │   │   login.js
              │   └───login.vue
              ├───pay
              │   │   pay_result.htm
              │   │   pay_result.js
              │   │   pay_result.vue
              │   │   pay.htm
              │   │   pay.js
              │   └───pay.vue
              └───...


          修改配置前的一些知識(shí)

          我們知道webpack的核心是一切皆模塊,所以它本質(zhì)上是一個(gè)靜態(tài)模塊打包器。當(dāng) webpack 處理應(yīng)用程序時(shí),它會(huì)遞歸地構(gòu)建一個(gè)依賴關(guān)系圖,其中包含應(yīng)用程序需要的每個(gè)模塊,然后將所有這些模塊打包成一個(gè)或多個(gè) bundle。

          官網(wǎng)顯示的這幅圖很形象地描述了這個(gè)過(guò)程。


          從 webpack v4.0.0 開(kāi)始,webpack 提供了一系列的配置默認(rèn)項(xiàng),讓開(kāi)發(fā)者可以零配置打包,不再?gòu)?qiáng)制要求必須進(jìn)行繁瑣的 webpack 配置,讓開(kāi)發(fā)者可以從繁瑣的配置文件里抽出,專注應(yīng)用的開(kāi)發(fā)。但是若你需要有特殊的處理,webpack 仍然可以進(jìn)行高度可配置來(lái)滿足你的需求。

          在開(kāi)始前需要了解四個(gè)核心概念:

          • 入口(entry):指示 webpack 應(yīng)該使用哪個(gè)模塊,來(lái)作為構(gòu)建其內(nèi)部依賴圖的開(kāi)始。


          • 輸出(output):指示 webpack 在哪里輸出它所創(chuàng)建的 bundles,以及如何命名這些文件


          • loader:讓 webpack 能夠去處理那些非 JavaScript 文件


          • 插件(plugins):可以讓 webpack 執(zhí)行范圍更廣的任務(wù)。


          本篇將會(huì)針對(duì)這4個(gè)核心配置的修改和優(yōu)化來(lái)實(shí)現(xiàn)多頁(yè)面打包。在 webpack4 的版本,還新增了一個(gè) mode 配置項(xiàng)。mode 有兩個(gè)值:development 或者是 production,用戶可以啟用相應(yīng)模式下的 webpack 內(nèi)置的優(yōu)化。不同 mode 的區(qū)別與默認(rèn)配置可以參考:https://segmentfault.com/a/1190000013712229


          一、入口配置

          在單頁(yè)面應(yīng)用里,一般在根目錄下面會(huì)有一個(gè) index.html 文件。它是頁(yè)面的 html 模板文件。但是在多頁(yè)面應(yīng)用里,則會(huì)有多個(gè)應(yīng)用模板文件,為了方便管理,可以將不同類的入口文件、邏輯處理和模板文件分別存放在相應(yīng)的獨(dú)立目錄。若用到了組件,則單獨(dú)將組件存放在一個(gè)目錄。

          project
          └───src
              ├───components
              │   │   count.vue
              │   │   dialog.vue
              │   │   errortips.vue
              │   └───...
              ├───game
              │   │   game.htm
              │   │   game.js
              │   └───game.vue
              ├───login
              │   │   login.htm
              │   │   login.js
              │   └───login.vue
              ├───pay
              │   │   pay_result.htm
              │   │   pay_result.js
              │   │   pay_result.vue
              │   │   pay.htm
              │   │   pay.js
              │   └───pay.vue
              └───...


          webpack 的入口配置中是支持多入口的,給 entry 傳入對(duì)象即可,如下所示:

          const config={
            entry: {
              game: './src/game/game.js',
              login: './src/login/login.js',
              pay: './src/pay/pay.js',
              pay_result: './src/pay/pay_result.js'
            }
          };

          但這樣的配置對(duì)于未知頁(yè)面數(shù)量的項(xiàng)目并不友好,若每新增頁(yè)面都要重新配置和重啟程序,顯然是不合理的。而我們可以創(chuàng)建一個(gè)getEntry()的方法來(lái)遍歷文件夾來(lái)獲取入口。

          const fs=require('fs');
          const glob=require("glob"); 
          function getEntry() {
              const entry={};
              //讀取src目錄所有page入口
              glob.sync('./src/*/*.js') //獲取符合正則的文件數(shù)組
                  .forEach(function (filePath) {
                      var name=filePath.match(/\/src\/(.+)\/*.js/);
                      name=name[1];
                      //須有配套的模板文件才認(rèn)為是入口
                      if (!fs.existsSync('./src/' + name + '.htm')) {
                          return;
                      }
                      entry[name]=filePath;
                  });
              return entry;
          };
          module.exports={
            // 多入口
            entry: getEntry(),
          }


          二、輸出配置

          輸出配置僅需指定一個(gè)

          const config={
              output: {
                  path: path.join(__projectDir, __setting.distJs),
                  publicPath: __setting.domainJs, //自定義變量,用來(lái)定義公共靜態(tài)資源路徑
                  filename: '[name][hash].js'
              },
          };
          • path:目標(biāo)輸出目錄的絕對(duì)路徑
          • publicPath:文件中靜態(tài)資源的引用路徑

          https://www.webpackjs.com/configuration/output/#output-publicpath

          • filename:用于輸出文件的文件名

          https://www.webpackjs.com/configuration/output/#output-filename

          在配置中有以下幾點(diǎn)需要注意:

          • publicPath

          publicPath 是指定在瀏覽器中所引用的「此輸出目錄對(duì)應(yīng)的公開(kāi) URL」。

          簡(jiǎn)單的例子:

          publicPath: "https://cdn.example.com/assets/"

          輸出到html則變成

          <script src="https://cdn.example.com/assets/bundle.js"></script>

          這個(gè)屬性是整個(gè)項(xiàng)目共用的靜態(tài)資源路徑,若某個(gè)模塊需要使用其他的靜態(tài)資源路徑。webpack 提供了__webpack_public_path__來(lái)動(dòng)態(tài)設(shè)置 publicPath,只需在入口文件的最頂部定義即可。

          __webpack_public_path__=myRuntimePublicPath; // 一定要寫在最頂部
          • hash

          filename的[hash]是以項(xiàng)目為維度的 hash 值,若輸出了多個(gè)文件,則文件名都會(huì)共用一個(gè) hash 值。

          filename的[chunkhash]是以chunk為維度生成的 hash 值,不同入口生成不同的 chunkhash 值。

          filename的[contenthash]根據(jù)資源內(nèi)容生成的 hash 值。

          通常使用 hash 或 chunkhash,contenthash 通常用于某些特殊場(chǎng)景(官方文檔在使用 ExtractTextWebpackPlugin 插件時(shí)有使用)。

          https://www.webpackjs.com/plugins/extract-text-webpack-plugin/


          三、loader配置

          由于 webpack 只能理解 JavaScript 和 JSON 文件。而配置 loader 就是讓 webpack 能夠去處理其他類型的文件,并將它們轉(zhuǎn)換為有效模塊。

          loader 可以使開(kāi)發(fā)者在 import 或"加載"模塊時(shí)預(yù)處理文件。例如,將內(nèi)聯(lián)圖像轉(zhuǎn)換為 data URL,或者允許開(kāi)發(fā)者直接在 JavaScript 模塊中 import CSS文件

          1、js 模塊

          加載js模塊,我們通常是為了引入babel,讓其能將ES6的語(yǔ)法轉(zhuǎn)成ES5,讓項(xiàng)目能在低版本的瀏覽器上運(yùn)行。

          js文件需要使用babel的話,引入babel-loader

          const config={
              module: {
                  rules: [{
                      test: /\.js$/,
                      include: [path.resolve(__projectDir, 'src')], //通過(guò)include精確指定只處理哪些目錄下的文件
                      exclude: /node_modules/, //設(shè)置哪些目錄里的文件不進(jìn)行處理
                      loader: "babel-loader"
                  }]
              }
          }

          但僅僅配置了babel-loader還不夠,還需要配置 babel 的環(huán)境,需要引入 polyfill。

          引入 polyfill 的方式有很多種,根據(jù) vue 官方文檔在瀏覽器兼容性的處理,默認(rèn)使用的是@vue/babel-preset-app ,它通過(guò)@babel/preset-env和browserslist配置來(lái)決定項(xiàng)目需要的 polyfill。

          https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/babel-preset-app


          browserslist

          項(xiàng)目根目錄創(chuàng)建.browserslist文件

          > 1%
          last 2 versions

          當(dāng)然,你也可以在package.json文件里添加的browserslist字段來(lái)配置。

          這個(gè)配置的目的是為了指定了項(xiàng)目的目標(biāo)瀏覽器的范圍,配置的值會(huì)被 @babel/preset-env 用來(lái)確定需要轉(zhuǎn)譯的 JavaScript 特性。

          詳細(xì)的說(shuō)明可以查閱 https://github.com/browserslist/browserslist,了解如何指定瀏覽器范圍。

          Polyfill

          項(xiàng)目根目錄創(chuàng)建.babelrc文件

          {
            "presets": [
              ["@babel/preset-env",
                {
                  "modules": false, // 對(duì)ES6的模塊文件不做轉(zhuǎn)化,以便使用tree shaking、sideEffects等
                  "useBuiltIns": "entry", // browserslist環(huán)境不支持的所有墊片都導(dǎo)入
                  "corejs": {
                    "version": 3, // 使用core-js@3
                    "proposals": true
                  }
                }
              ]
            ]
          }

          這里特別說(shuō)下的是配置里的useBuiltIns,可設(shè)置的值分別是"usage" | "entry" | false,3個(gè)值分別代表:

          • usage 會(huì)根據(jù)配置的瀏覽器兼容,以及你代碼中用到的 API 來(lái)進(jìn)行 polyfill,實(shí)現(xiàn)了按需添加。
          • entry 根據(jù)配置的瀏覽器兼容,引入瀏覽器不兼容的 polyfill。這時(shí)會(huì)自動(dòng)根據(jù) browserslist 替換成瀏覽器不兼容的所有 polyfill。
          • false 此時(shí)不對(duì) polyfill 做操作。如果引入@babel/polyfill,則無(wú)視配置的瀏覽器兼容,引入所有的 polyfill。

          項(xiàng)目使用的是"useBuiltIns": "entry",所以需要指定corejs的版本,這里使用的版本是core-js@3,所以我們?cè)?webpack 的入口配置里加上"core-js/stable"和 "regenerator-runtime/runtime"。

          function getEntry() {
              const entry={};
              //讀取src目錄所有page入口
              glob.sync('./src/*/*.js') //獲取符合正則的文件數(shù)組
                  .forEach(function (filePath) {
                      var name=filePath.match(/\/src\/(.+)\/*.js/);
                      name=name[1];
                      //須有配套的模板文件才認(rèn)為是入口
                      if (!fs.existsSync('./src/' + name + '.htm')) {
                          return;
                      }
                      entry[name]=["core-js/stable", "regenerator-runtime/runtime", path.join(__projectDir, filePath)];
                  });
              return entry;
          };


          2、css 模塊

          我們通常使用style-loader和css-loader。css-loader用來(lái)處理 js 文件中引入的 css 模塊(處理@import和url()),style-loader是將css-loader打包好的css代碼以<style>標(biāo)簽的形式插入到 html 文件中。而 webpack 對(duì)于 loader 的調(diào)用是從右往左的,所以通常是這樣配置:

          {
              test: /\.css$/,
              use: [ 'style-loader', 'css-loader' ]
          }

          我們?cè)陧?xiàng)目中還經(jīng)常會(huì)使用 sass 或者 scss。sass 是一種 CSS 的預(yù)編譯語(yǔ)言。因此 webpack 要將其處理會(huì)使用更多 loader。

          {
              test: /\.(sc|sa)ss$/,
              use: [{
                  loader: 'vue-style-loader'
              }, {
                  loader: 'css-loader',
                  options: {
                      sourceMap: true,
                  }
              }, {
                  loader: 'postcss-loader',
                  options: {
                      sourceMap: true
                  }
              }, {
                  loader: 'sass-loader',
                  options: {
                      sourceMap: true
                  }
              }, {
                  loader: 'sass-resources-loader', //組件里面使用全局scss
                  options: {
                      sourceMap: true,
                      resources: [
                          path.resolve('./src/public/css/common.scss')
                      ]
                  }
              }]
          }

          在使用sass-loader的時(shí)候若某個(gè) scss 文件(比如a.scss)@import 了其他 scss 文件(比如b.scss),如果b.scss里的url()的路徑是相對(duì)路徑,在sass-loader處理過(guò)后給css-loader處理時(shí)就會(huì)報(bào)錯(cuò),找不到url()里指定的資源。

          這是因?yàn)閟ass-loader處理時(shí),會(huì)將 scss 文件里 @import 路徑的文件一并合并進(jìn)來(lái),結(jié)合上面的例子就是b.scss會(huì)被sass-loader合并進(jìn)a.scss。

          如何解決呢?可以有兩個(gè)解決方法:

          • 將資源路徑改為變量來(lái)統(tǒng)一管理
          • 通過(guò) alias 設(shè)置路徑別名,從而便捷使用絕對(duì)路徑。注意在scss文件中使用 alias 里定義的路徑別名時(shí),需要帶上~前綴,否則打包時(shí)仍會(huì)被識(shí)別為普通路徑。

          在項(xiàng)目中由于還用到了postcss-loader,我們還須要在根目錄創(chuàng)建postcss-loader的配置文件postcss.config.js

          //自動(dòng)添加css瀏覽器前綴
          module.exports={
              plugins: [
                  require('autoprefixer')
              ]
          }


          3、圖片等靜態(tài)資源

          對(duì)于圖片資源的打包,經(jīng)常會(huì)使用file-loader來(lái)完成,配置也很簡(jiǎn)單:

          {
            test: /\.(gif|png|jpe?g)$/,
            loader: 'file-loader',
          }

          打包后,會(huì)將圖片移動(dòng)到了 dist 目錄下,并將該圖片改名為[hash].[ext]格式的圖片。開(kāi)發(fā)者也可以根據(jù)需要,修改輸出的文件名。

          但在項(xiàng)目開(kāi)發(fā)過(guò)程中,我們會(huì)創(chuàng)建很多張圖片,這就使得頁(yè)面在加載是時(shí)候會(huì)發(fā)送很多http請(qǐng)求,當(dāng)頁(yè)面圖片過(guò)多,會(huì)影響的頁(yè)面的性能。所以,這里推薦使用url-loader。

          {
              test: /\.(png|jpg|jepg|svg|gif)$/,
              use: [{
                  loader: 'url-loader',
                  options: {
                      limit: 10240, //這里的單位是b
                      name: 'image/[name][hash].[ext]' //打包后輸出路徑
                  }
              }]
          }

          使用url-loader我們可以通過(guò)設(shè)置limit的值,將文件大小小于某個(gè)值的圖片打包成base64的形式存放在打包后的 js 中,若超過(guò)了這個(gè)設(shè)定值,默認(rèn)會(huì)使用file-loader(所以雖然代碼沒(méi)有配置 file-loader,但還是需要使用安裝file-loader),并且會(huì)將配置的選項(xiàng)傳遞給file-loader。


          4、import AMD 模塊

          有時(shí)我們需要在項(xiàng)目里使用一些 AMD 模塊或者完全不支持模塊化的庫(kù)。例如移動(dòng)端經(jīng)常使用的 zepto。如果我們直接使用 import zepto 的方式引入是會(huì)報(bào)錯(cuò)的:Uncaught TypeError: Cannot read property 'createElement' of undefined

          要使用也很簡(jiǎn)單,使用script-loader和exports-loader即可:

          {
              test: require.resolve('zepto'),
              use: ['exports-loader?window.Zepto','script-loader']
          }
          • script-loader 用 eval 的方法將 zepto 在引入的時(shí)候執(zhí)行了一遍,此時(shí) zepto 庫(kù)已存在于 window.Zepto
          • exports-loader 將傳入的 window.Zepto 以 module.exports=window.Zepto 的形式向外暴露接口,使這個(gè)模塊符合 CommonJS 規(guī)范,支持 import 這樣我們就可以直接import $ from 'zepto'了,其他 AMD 模塊或者其他不支持模塊化的庫(kù)也類似。



          四、plugins

          webpack 可以使用插件(plugins)來(lái)讓開(kāi)發(fā)者能夠在打包的過(guò)程中實(shí)現(xiàn)更多功能,插件會(huì)在整個(gè)構(gòu)建過(guò)程中生效,并執(zhí)行相關(guān)的任務(wù)。這里會(huì)介紹幾個(gè)比較實(shí)用的插件:

          1、mini-css-extract-plugin

          在使用style-loader處理后,css 文件會(huì)作為模塊打包進(jìn) js 文件里。若我們想將 js 文件和 css 文件分離。就可以使用mini-css-extract-plugin:

          module: {
              rules: [{
                  test: /\.css$/,
                  use: [{
                      loader: MiniCssExtractPlugin.loader
                  },
                      'css-loader'
                  ]
              }]
          },
          plugins: [
              new MiniCssExtractPlugin({
                  filename: 'css/[hash].css'
              })
          ]


          2、copy-webpack-plugin

          有時(shí)候我們會(huì)有一些沒(méi)經(jīng)過(guò)打包的文件需要復(fù)制到我們的生產(chǎn)目錄里,copy-webpack-plugin就可以實(shí)現(xiàn)這個(gè)功能。

          plugins: [
              new CopyWebpackPlugin([
                  {
                      from: { glob: './src/public/*.htm', dot: true },
                      to: path.join(__setting.distTpl, 'public','[name].htm')
                  }
              ], { copyUnmodified: true })
          ]


          3、html-webpack-plugin

          我們前面介紹入口配置的時(shí)候會(huì)看到只配置了 js 文件,只是因?yàn)?webpack 現(xiàn)在入口只支持 js 文件,所以打包輸出的也是 js 文件,那如果我們需要將 js 文件引入到 html 里,就需要使用到html-webpack-plugin插件。

          html-webpack-plugin在使用的時(shí)候,是必須一個(gè)入口對(duì)應(yīng)一個(gè)配置的,所以我們前面使用了多頁(yè)面的配置,也需要進(jìn)行相應(yīng)的修改,修改后的getEntry方法:

          const htmlPluginArray=[];
          function getEntry() {
              const entry={};
              //讀取src目錄所有page入口
              glob.sync('./src/' + __setting.moduleId + '/*.js')
                  .forEach(function (filePath) {
                      var name=filePath.match(/\/src\/(.+)\/*.js/);
                      name=name[1];
                      if (!fs.existsSync(path.join(__projectDir, './src/' + name + '.htm'))) {
                          return;
                      }
                      entry[name]=["core-js/stable", "regenerator-runtime/runtime", path.join(__projectDir, filePath)];
          +           htmlPluginArray.push(new HtmlWebpackPlugin({
          +               filename: `${__setting.distTpl}/${name}.htm`,
          +               template: './src/' + name + '.htm',
          +               inject: 'body',
          +               minify: {
          +                   removeComments: true,
          +                   collapseWhitespace: true
          +               },
          +               chunks: [name],
          +               inlineSource: '.(js|css)'
          +           }))
                  });
              return entry;
          };
          
          
          // 配置plugin,由于plugins通常使用數(shù)組類型來(lái)配置,
          // 所以可以使用concat方法將配置好的html的數(shù)組添加進(jìn)去。
          plugins: [
              new MiniCssExtractPlugin({
                  filename: 'css/[hash].css'
              })
          ].concat(htmlPluginArray),


          里面的一些配置是要注意一下的:

          • filename

          filename 是配置需要將 html 改成什么名字并輸出到哪里的配置。這里配置的的路徑是以 output 里配置的path為相對(duì)路徑的,我們上面 output 配置的是

          path: path.join(__projectDir, __setting.distJs)

          那最終的html輸出路徑就是

          path.join(__projectDir, __setting.distJs, 
          `${__setting.distTpl}/${name}.htm`)
          • minify

          是將html里的代碼進(jìn)行壓縮。如果 minify 選項(xiàng)設(shè)置為 true 或者配置對(duì)象 ( true 是 webpack 模式為 production 時(shí)的默認(rèn)值),生成的 HTML 將使用 HTML-minifier壓縮代碼,更多具體的配置可以看這里minification。

          • 其他

          template 生成 filename 文件的模版。重點(diǎn):與 filename 的路徑不同, 當(dāng)匹配模版路徑的時(shí)候?qū)?huì)從項(xiàng)目的根路徑開(kāi)始。

          inject 制定 webpack 打包的 js css 靜態(tài)資源插入到 html 的位置。

          chunks 指定模板允許添加哪個(gè)入口文件。若不配置這個(gè)會(huì)將所有的入口都添加進(jìn)來(lái)。


          4、html-webpack-inline-source-plugin

          若我們想將打包好的 js 代碼 inline 進(jìn) html 的話,就要使用到html-webpack-inline-source-plugin

          可以看到上面html-webpack-plugin的配置里有inlineSource: '.(js|css)'

          這就是告訴html-webpack-inline-source-plugin需要將打包好的代碼 inline 進(jìn) html 里,插件需要添加到html-webpack-plugin的配置后

          plugins: [
              new MiniCssExtractPlugin({
                  filename: 'css/[hash].css'
              })
          ].concat(htmlPluginArray).concat([
              new HtmlWebpackInlineSourcePlugin()
          ])

          但是html-webpack-inline-source-plugin也僅能將打包后輸出的 js 文件引入 html,若你想將 html 碼其他使用 script 標(biāo)簽加載的 js 文件或者 style 標(biāo)簽加載的 css 文件也 inline 進(jìn) html 里的話,html-webpack-inline-source-plugin并不能實(shí)現(xiàn)。從html-webpack-plugin里的 Issues 來(lái)看,html-webpack-plugin的作者也無(wú)意做這樣的事情,但也給出了建議,可以借助html-webpack-plugin插件的 hooks html-webpack-plugin-before-html-processing達(dá)到我們需要的效果。


          5、自定義插件

          上面說(shuō)到要將外部的靜態(tài)文件也 inline 進(jìn) html,我們可以編寫自定義插件,借助html-webpack-plugin插件的 hooks html-webpack-plugin-before-html-processing,再結(jié)合inline-source組件來(lái)實(shí)現(xiàn)我們的功能。

          const {
              inlineSource
          }=require('inline-source');//加載inline-source組件
          //定義方法
          function scriptInlineHtml(options) {
              // Configure your plugin with options...
              this.options=options || {};
          }
          
          
          scriptInlineHtml.prototype.apply=function (compiler) {
              let that=this;
              (compiler.hooks ? //判斷webpack版本,4.0以上和4.0以下的處理不一樣
                  compiler.hooks.compilation.tap.bind(compiler.hooks.compilation, 'script-inline-html') :
                  compiler.plugin.bind(compiler, 'compilation'))(function (compilation) {
                      (compilation.hooks ?
                          compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tapAsync.bind(compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing, 'script-inline-html') :
                          compilation.plugin.bind(compilation, 'html-webpack-plugin-before-html-processing'))(async function (htmlPluginData, callback) {
          
          
                              //獲取的html內(nèi)容處理后重新賦值;
                              try {
                                  htmlPluginData.html=await inlineSource(htmlPluginData.html, that.options);
                                  // Do something with html
                              } catch (err) {
                                  // Handle error
                              }
                              //繼續(xù)執(zhí)行下個(gè)插件
                              callback(null, htmlPluginData);
                          });
                  });
          };
          //webpack插件添加
          plugins: [
              new MiniCssExtractPlugin({
                  filename: 'css/[hash].css'
              })
          ].concat(htmlPluginArray).concat([
              new scriptInlineHtml(),
              new HtmlWebpackInlineSourcePlugin()
          ])

          使用

          <script src="/src/public/js/px2rem.js" inline></script>

          這里結(jié)合 inline 靜態(tài)資源,簡(jiǎn)單介紹了自定義插件的使用,在html-webpack-plugin構(gòu)建 html 過(guò)程中,還提供其他一系列的事件。

          Async:

          • html-webpack-plugin-before-html-generation
          • html-webpack-plugin-before-html-processing
          • html-webpack-plugin-alter-asset-tags
          • html-webpack-plugin-after-html-processing
          • html-webpack-plugin-after-emit

          Sync:

          • html-webpack-plugin-alter-chunks

          這些事件可以讓我們?cè)跇?gòu)建 html 的不同階段里,通過(guò)一些處理來(lái)達(dá)到我們的目的。例如:可以結(jié)合smarty.js將使用了 smarty 的模板,引入一些模擬數(shù)據(jù)后解析成正常的html代碼;讀取 HTML 文件進(jìn)行翻譯文本的替換,實(shí)現(xiàn)頁(yè)面的多語(yǔ)言化。打包不同皮膚的html文件等等。



          五、其他配置

          1、resolve

          resolve 配置規(guī)定了 webpack 如何尋找各個(gè)依賴模塊。

          前面有講到使用 alias 設(shè)置路徑別名。在資源引用時(shí),如果資源引用路徑太深,又比較常用,我們可以定義路徑別名,例如:

          resolve: {
              alias: {
                  '@': path.resolve(__projectDir, 'src')
              }
          }

          我們就可以直接在代碼中這樣引用了:

          let backimg=require("@/public/image/common/ico-back.png").default;


          2、webpack dev server

          webpack-dev-server是開(kāi)發(fā)時(shí)的必備利器,它可以在本地起一個(gè)簡(jiǎn)單的 web 服務(wù)器,當(dāng)文件發(fā)生變化時(shí),能夠?qū)崟r(shí)重新加載。webpack-dev-server的配置也很簡(jiǎn)單:

          devServer: {
              contentBase: __projectDir, //頁(yè)面的基礎(chǔ)目錄
              publicPath:'/',
              port: 8080,
              host: '127.0.0.1',
              open: true, //是否運(yùn)行后自動(dòng)打開(kāi)瀏覽器
              hot: true
          }

          啟動(dòng) webpack-dev-server 后,在目標(biāo)文件夾中是看不到編譯后的文件的,實(shí)時(shí)編譯后的文件都保存到了內(nèi)存當(dāng)中。

          1) HMR

          hot設(shè)置為 true 是啟用 webpack 的 模塊熱替換( HMR )功能,但這里注意必須要添加插件webpack.HotModuleReplacementPlugin 才能完全啟用 HMR

          2) publicPath

          publicPath 路徑下的打包文件可以在瀏覽器中訪問(wèn),webpack-dev-server 打包的內(nèi)容是放在內(nèi)存中的,并沒(méi)有實(shí)際創(chuàng)建文件,這些打包后的資源對(duì)外的的根目錄就是 publicPath。

          默認(rèn) devServer.publicPath 是 '/',所以你的包( bundle )可以通過(guò) http://127.0.0.1:8080/bundle.js 訪問(wèn)。注意:當(dāng)這里的 publicPath 和 output 的 publicPath 同時(shí)設(shè)置時(shí),這里的優(yōu)先級(jí)更高。


          總結(jié)

          webpack 的配置能介紹的點(diǎn)其實(shí)還有很多,例如開(kāi)發(fā)環(huán)境和生產(chǎn)環(huán)境進(jìn)行配置分離;利用瀏覽器的緩存將公共的模塊抽離分開(kāi)打包;還有很多常用 plugins 插件等等。

          這篇文章是以我在開(kāi)發(fā)某個(gè)多頁(yè)面應(yīng)用項(xiàng)目為例,總結(jié)了一些我在webpack配置上的理解。希望能對(duì)瀏覽這篇文章的小伙伴有幫助。



          作者:HZH

          來(lái)源-微信公眾號(hào):三七互娛技術(shù)團(tuán)隊(duì)

          出處:https://mp.weixin.qq.com/s/JzZDqe-f_NRMmdxDLXC7tQ

          包html需要用到一個(gè)插件html-webapck-plugin。

          npm i html-webpack-plugin -D

          package.json需要的開(kāi)發(fā)依賴如下:

          {
            "name": "wpk5-demo",
            "version": "1.0.0",
            "description": "",
            "main": "index.js",
            "scripts": {
              "test": "echo \"Error: no test specified\" && exit 1"
            },
            "keywords": [],
            "author": "",
            "license": "ISC",
            "devDependencies": {
              "html-webpack-plugin": "^5.3.1",
              "webpack": "^5.28.0",
              "webpack-cli": "^4.5.0"
            }
          }

          webpack.config.js的配置如下:

          const { resolve }=require('path');
          const HtmlWebpackPlugin=require('html-webpack-plugin');
          module.exports={
              entry: './src/main.js',
              output: {
                  filename: 'bundle.js',
                  path: resolve(__dirname, 'dist')
              },
              module: {
                  rules: []
              },
              plugins: [
                  new HtmlWebpackPlugin({
                      template: './src/assets/index.html',
                      hash: true,
                      filename: 'index.html',
                      favicon: './src/assets/favicon.ico'
                  })
              ],
              mode: 'development'
          }

          代碼倉(cāng)庫(kù):https://gitee.com/seimin/xiaoming2qianduan-webpack5/tree/v5.1/


          主站蜘蛛池模板: 国产一区高清视频| 日本不卡一区二区三区| 精品国产日产一区二区三区| 精品免费国产一区二区| 成人精品一区二区三区不卡免费看 | 久久精品视频一区二区三区| 亚洲AV无码一区二区三区人| 91在线精品亚洲一区二区| 日本一区二区三区精品国产| 日韩精品无码一区二区三区四区| 在线不卡一区二区三区日韩| 久久久精品人妻一区二区三区四| 日韩精品一区二区三区不卡| 国产吧一区在线视频| 亚洲AV一区二区三区四区 | 一区二区国产在线播放| 亚洲Av无码国产一区二区| 中文字幕精品亚洲无线码一区| 国产精品高清一区二区人妖| 尤物精品视频一区二区三区 | 亚洲av成人一区二区三区在线观看| 老湿机一区午夜精品免费福利| 青娱乐国产官网极品一区| 一区二区三区AV高清免费波多| 精品一区二区在线观看| 国产精品视频一区麻豆| 亚洲啪啪综合AV一区| 国产成人精品一区二三区 | 精品免费国产一区二区| 中文字幕一区二区区免| 国产免费一区二区三区不卡| 日韩精品成人一区二区三区| 国产高清视频一区二区| 国产日本亚洲一区二区三区| 国产一区二区三区精品视频| 亚洲日韩中文字幕一区| 冲田杏梨高清无一区二区| 精品无码av一区二区三区| 午夜视频久久久久一区 | 无码人妻精品一区二区三区蜜桃 | 日韩视频在线一区|