WEBPACK + JSP 構建多頁應用

nqdy666發表於2018-01-22

概述

傳統的JSP頁面應用無法有效的使用ES6語法特性,專案打包壓縮困難,無法熱更新。傳統的單頁應用在Tomcat等容器下無法進行服務端渲染到達SEO的效果。本專案工程很好融合的傳統JSP頁面服務端渲染的特點和單頁應用開發特性且極易上手使用!

原始碼地址

原始碼地址

Demos與文件

Demos與文件

特性

  • 多頁應用
  • JSP巢狀
  • el表示式
  • 服務端渲染(SEO)
  • 熱部署
  • js,css語法轉換
  • eslint
  • 熱更新
  • 支援Vue
  • 打包壓縮
  • IE9+支援傳統JSP開發所的所有功能;可以通過自定義webpack配置來實現對react的支援;通過引入vue-router和vuex某一個頁面完成可以變成一個單頁應用。

如果您想要支援IE8,那需要把webpack降級,因為webpack2+是不支援IE8的,以及儘量避免去使用不支援IE8的庫,比如jquery2+,lodash4+, Vue等,祝您好運。

環境搭建

工欲善其事,必先利其器。

  • JDK1.7+
  • IntelliJ IDEA,需要安裝js相關外掛和配置支援es6語法。
  • Maven3+
  • Tomcat7+,埠預設請使用8080
  • Git bash
  • npm3+
  • node7+

如果您喜歡編輯js和css的時候用vscode也是沒有問題,不過編寫jsp和java還是推薦用idea。

以下總結環境配置的相關文章,可供參考JDK下載地址IntelliJ IDEA配置前端開發環境IntelliJ IDEA配置JAVA WEB的Tomcat環境maven下載安裝Git Bash下載安裝

目錄說明

├── pom.xml   // maven配置檔案├── src|  ├── main|  |  ├── filters|  |  |  └── resources // java工程資源配置目錄|  |  ├── java // java程式碼目錄|  |  ├── js // 前端頁面工程|  |  |  ├── build  // 編譯相關以及webpack相關配置|  |  |  |  ├── build.js|  |  |  |  ├── check-versions.js|  |  |  |  ├── logo.png|  |  |  |  ├── utils.js|  |  |  |  ├── webpack.base.conf.js|  |  |  |  ├── webpack.dev.conf.js|  |  |  |  └── webpack.prod.conf.js|  |  |  ├── config // 配置相關|  |  |  |  ├── dev.env.js|  |  |  |  ├── index.js|  |  |  |  ├── js-jsp-map.js // 配置入口js和jsp的對映|  |  |  |  └── prod.env.js|  |  |  ├── package.json // npm配置|  |  |  ├── src // web專案工程目錄|  |  |  |  ├── pages // jsp頁面,最終的jsp檔案們會按照pages相對路徑打包進webapp/WEB-INF/jsp目錄下|  |  |  |  |  ├── include // 共享的jsp頁面,通過jsp:include引入|  |  |  |  |  |  ├── common_script.jsp|  |  |  |  |  |  ├── footer.jsp|  |  |  |  |  |  ├── header.jsp|  |  |  |  |  |  ├── init.jsp|  |  |  |  |  |  └── meta.jsp|  |  |  |  |  ├── index // 頁面1|  |  |  |  |  |  ├── index.js // 需要在在config/js-jsp-map.js配置與jsp的對映關係,這樣編譯後的js會載入jsp的body下。一般js與jsp在同一個目錄下。|  |  |  |  |  |  └── index.jsp|  |  |  |  |  └── start // 頁面2|  |  |  |  |     ├── dashboard.css|  |  |  |  |     ├── index.js|  |  |  |  |     └── index.jsp|  |  |     |     └── my-component.vue 支援VUE|  |  |     ├── polyfills 相容相關的程式碼|  |  |     |  ├── console.js|  |  |     |  ├── index.js|  |  |     |  └── promise.js|  |  |     ├── static // 存在靜態檔案,最終這些檔案會拷貝到webapp目錄下|  |  |     |  ├── favicon.ico|  |  |     |  ├── images|  |  |     |  |  ├── jsp.svg|  |  |     |  |  └── webpack.svg|  |  |     |  ├── js|  |  |     |  |  └── lib|  |  |     |  |     └── jquery.min.js|  |  |     |  └── WEB-INF|  |  |     |     ├── tld|  |  |     |     └── web.xml|  |  |     └── styles|  |  └── webapp // 該目錄下的檔案不用開發人員手動新增修改,在npm run dev或npm run build的時候自動生成。|  └── test|     └── java複製程式碼

src/main/js目錄下的目錄結構是在vue-cli的webpack模板的基礎上修改的,如果您使用過該模板建立過專案,那麼將很容易會上手。

開發

cd src/main/jsnpm run dev

在idea中啟動tomcat

在瀏覽器中開啟http://localhost:8081

以下幾點需要注意一下

首次啟動專案,建議先npm run dev在啟動tomcat。之後其中一個重啟,另外一個可以不用重啟。預設情況下npm run dev跑在8081埠下,tomcat跑在8080埠下。最終在瀏覽器訪問只需要訪問8081的頁面,8080頁面沒有必要。開發模式下,js引入的css是動態引入的,頁面會出現閃變的效果。不用擔心,在釋出後的環境中是不會出現的。開發jsp頁面的時候,熱部署會有延時,具體參看JSP頁面這一章節開發jsp檔案務必在pages目錄下開發,切勿在webapp目錄下開發。否則在切換到pages目錄下開發或者打包後或,webapp下的jsp的檔案會被覆蓋,導致修改的內容丟失。

打包釋出

npm run build

webapp作為輸出目錄,static中檔案會拷貝到輸出目錄,pages目錄下的jsp檔案會作為模板檔案拷貝到webapp/WEB-INF/jsp目錄下,與jsp關聯的js入口會被合併壓縮後引入到jsp檔案的body中。jsp關聯的css會被抽離出一個單個的css檔案引入的jsp檔案head中。

如果您打包後的應用的Application Context不是/, 比如是/app,即訪問地址都是基於http://localhost:8080/app,那麼打包的時候webpack的publicPath引數記得配置/app,且jsp頁面中所有的地址都需要帶上${pageContext.request.contextPath
}/
,在該專案框架中可以簡寫為${ctx
}/

JSP頁面

傳統的JSP是在src/main/webapp下開發,在這個專案框架下開發jsp檔案是在src/main/js/src/pages下開發。雖然開發目錄不一致,但依然擁有傳統jsp開發所有的特性。

  • 模板巢狀,比如使用<
    jsp:include page=''>
    <
    /jsp:include>
    或者<
    %@include file=""%>
  • el表示式,<
    c:set>
    , <
    c:if>
    , <
    c:forEach>
    等都可以使用
  • 嵌入Java程式碼 比如使用<
    % out.println("hello world");
    %>
  • 支援熱部署。配置好啟動tomcat相關引數。在修改完jsp儲存檔案後,約10秒後重新整理頁面就可以看到頁面的變化。如果等不及10秒或者頁面一直不重新整理,可以先點選idea選單File->
    Syncronize>
    同步檔案(快捷鍵Ctrl+Alt+Y),然後在點選Run的左側第三個按鈕後選擇Update classes and resources手動更新,之後就重新整理頁面就可以看到最新出的頁面。實際在npm run dev的時候,pages目錄下的jsp會作為htmlWebpackPlugin外掛的模板檔案,每次修改pages下的檔案都會被輸出到webapp/WEB-INF/jsp下的相對目錄。需要了解具體原理,請前往核心章節

自定義標籤庫

除了標準的c, fmt, fn標籤庫外,您也可以自定義標籤庫。

  • 首先在static/WEB-INF/tld新建一個tld,比如elftld
  • 然後jsp頁面引入,<
    %@ taglib prefix="elf" uri="/WEB-INF/tld/elfunc.tld" %>

注意的是,在jsp頁面的地址必須以/WEB-INF/開頭,而實際開發jsp的路徑是在js/src/pages目錄下,導致idea無法正常解析pages目錄下jsp中tld檔案路徑,在使用自定義標籤的時候也無法自動補全。不過可以正常執行,實際開發過程影響不大。如果您有更好的解決方案,請與我們聯絡。

語法轉換

因為了使用了webpack作為打包工具,您可以輕鬆對js和css進行語法轉換,目前支援:

  • es6, stage-2
  • postcss
  • less, sass, scss 需要額外裝對應的loader即可支援

熱更新

在開發單頁應用的過程中,有一個很棒的特性就是熱更新,修改了js檔案,頁面實時就會觸發更新。在此專案框架下,您依然可以享受到熱更新帶來的喜悅,在您修改js和css的時候,頁面都會實時觸發更新。

VUE

該專案已經預設支援Vue。這一章節也是用VUE編寫的,你可以盡情的享受VUE帶來的編碼的快樂。

  • 您可以給idea新增vue.js外掛,這樣也可以直接使用.vue檔案。
  • js和css的語法轉換在.vue檔案中同樣適用。

核心

該專案融合了webpack和jsp兩者的特性實現了多頁應用,這很酷。那到底是如何實現的呢。這裡我們從搭建專案遇到的問題來講講最核心的幾個問題是如何解決的。

HtmlWebpackPlugin

使用webpack實現多頁應用,很容易聯想到配置多個entry入口,每一個entry對應一個HtmlWebpackPlugin。jsp檔案作為HtmlWebpackPlugin的模板檔案,在entry的js在打包之後會插入到body下。該專案也是按照這樣的搭建的。這裡有幾點需要注意

  • HtmlWebpackPlugin解析jsp檔案需要對應的loader,需要在webpack中配置{
    test: /\.jsp$/, loader: 'raw-loader'
    }
    ,這裡使用raw-loader進行純文字拷貝。如果您有更適合jsp的loader,那麼您可以賦予jsp檔案特多的特性。
  • 因為jsp可以被巢狀,這些被巢狀的jsp,並不是入口的jsp。所有隻有是入口的jsp在配合HtmlWebpackPlugin外掛的會額外新增{inject: ‘body’
    }引數
  • 那如何規定哪些jsp是入口檔案呢?我們是通過配置來約定entry的js與jsp的關聯關係,配置檔案在config/js-jsp-map.js中。

proxy反代

tomcat是跑在8080埠下的,webpack-dev-server是跑在8081埠下的,是兩個不同應用。那豈不是開發jsp要在tomcat下編寫除錯,開發js在webpack-dev-server除錯。這樣的話豈不是很麻煩。

慶幸的webpack-dev-server有一個proxy引數,我們利用proxy把訪問webpack-dev-server的請求都反代到8080下。這樣實際開發過程中瀏覽器只要開啟8081埠頁面就可以。這樣就做到兼顧jsp服務端渲染的功能,以及webpack語法轉換,熱更新的功能。tomcat只有在必要的時候重啟一下就好。這裡有幾點需要注意

  • npm run dev和啟動tomcat並沒有順序要求,不過在瀏覽器訪問8081前需要把這兩個服務都啟動起來。
  • 當涉及到jsp檔案有新增刪除,或者static目錄下的檔案有新增編輯刪除時,需要重新npm run dev和重啟tomcat。記住一點,如果有檔案新增和刪除,最好都把這兩個服務都重啟一下肯定是沒有問題的。

WriteFilePlugin

我們知道webpack-dev-server是使用記憶體中的檔案系統。而jsp頁面最終是要釋出到tomcat的,記憶體中的jsp檔案並不能被idea監聽,這樣即使最終輸出的jsp發生改變也無法被deploy到tomcat。慶幸我們找到了一個webpack的外掛WriteFilePlugin,它能強制把webpack-dev-server程式的輸出的檔案寫到磁碟檔案系統上。這裡有幾點需要注意

  • 雖然通過WriteFilePlugin的jsp檔案輸出到磁碟上了,但是因為不是通過idea直接修改,idea還是無法立刻同步這些檔案。idea同步併發布jsp檔案會有10s的延遲。如果等不及10秒或者頁面一直不重新整理,可以先點選idea選單File->
    Syncronize>
    同步檔案(快捷鍵Ctrl+Alt+Y),然後在點選Run的左側第三個按鈕後選擇Update classes and resources手動更新,之後就重新整理頁面就可以看到最新出的頁面。

結語

這個思路其實不僅適用tomcat下的jsp多頁應用,同樣也是適用node作為伺服器的多頁應用。Enjoy it!

來源:https://juejin.im/post/5a620b0c6fb9a01cb3164346

相關文章