Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
pring Boot 微服務(wù)項(xiàng)目通常是通過 REST API 來提供服務(wù)的,而不是直接集成 HTML 頁面。不過,今天看到有小伙伴在咨詢?nèi)绾卧?Spring Boot 項(xiàng)目中集成 HTML 頁面,簡單整理了一下,可以采用以下常用的方法:
舉例來說,如果你選擇使用 Thymeleaf,可以按照以下步驟來實(shí)現(xiàn):
--1 在 pom.xml 中添加以下依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
--2 在 application.properties 中添加以下配置:
# 配置 Thymeleaf 模板文件所在路徑
spring.thymeleaf.prefix=classpath:/templates/
# 配置 Thymeleaf 模板文件后綴名
spring.thymeleaf.suffix=.html
# 配置 Thymeleaf 模板文件字符集
spring.thymeleaf.encoding=UTF-8
# 開啟緩存
spring.thymeleaf.cache=true
--3 在 src/main/resources/templates 目錄下創(chuàng)建 HTML 模板文件,并使用 Thymeleaf 標(biāo)簽進(jìn)行動(dòng)態(tài)數(shù)據(jù)綁定和條件渲染等操作。
例如,以下是一個(gè)簡單的 HTML 模板文件 index.html:
<!DOCTYPE html>
<html>
<head>
<title>Spring Boot + Thymeleaf</title>
</head>
<body>
<h1>Welcome to Spring Boot</h1>
<p th:text="${message}">This is a placeholder text.</p>
</body>
</html>
--4 在 Spring Boot 應(yīng)用程序的控制器中,使用 @GetMapping 注解定義一個(gè)返回 ModelAndView 對(duì)象的請(qǐng)求處理方法,并將模板文件名和動(dòng)態(tài)數(shù)據(jù)傳遞給 ModelAndView 對(duì)象。
例如,以下是一個(gè)簡單的控制器類 HomeController:
@Controller
public class HomeController {
@GetMapping("/")
public ModelAndView index() {
ModelAndView modelAndView = new ModelAndView("index");
modelAndView.addObject("message", "Hello, world!");
return modelAndView;
}
}
這樣,在瀏覽器中訪問 http://localhost:8080 就可以看到渲染后的 HTML 頁面了。
再舉一個(gè)FreeMarker的例子來簡單說一下:
當(dāng)使用Spring Boot構(gòu)建Web應(yīng)用程序時(shí),可以使用FreeMarker作為模板引擎來渲染HTML頁面。FreeMarker是一個(gè)開源的Java模板引擎,它允許您通過定義模板來生成HTML等文檔。下面是在Spring Boot項(xiàng)目中集成FreeMarker的一些常用方法:
--1 添加依賴:在項(xiàng)目的pom.xml文件中添加FreeMarker的依賴項(xiàng):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
--2 配置視圖解析器:在application.properties文件中添加以下配置,以告訴Spring Boot使用FreeMarker作為模板引擎來解析視圖:
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.ftl
--3 創(chuàng)建模板文件:在src/main/resources/templates目錄下創(chuàng)建.ftl文件,該文件將用于渲染HTML頁面。在模板文件中,您可以使用FreeMarker的模板語言來定義HTML頁面的內(nèi)容。
例如,以下是一個(gè)簡單的模板文件,它將渲染一個(gè)包含“Hello World”的HTML頁面:
<!DOCTYPE html>
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>${message}</h1>
</body>
</html>
在上面的模板中,${message}將被替換為實(shí)際的值。您可以在Java代碼中使用模型來設(shè)置這個(gè)值。
--4 創(chuàng)建控制器:在Spring Boot應(yīng)用程序中創(chuàng)建一個(gè)控制器,以處理HTTP請(qǐng)求并返回模板的名稱和模型。以下是一個(gè)示例控制器:
@Controller
public class HomeController {
@GetMapping("/")
public String home(Model model) {
model.addAttribute("message", "Hello World!");
return "home";
}
}
在上面的示例中,控制器返回了“home”字符串,這將作為模板文件的名稱。它還將模型添加到視圖中,該模型包含名為“message”的屬性和“Hello World!”的值。
這是在Spring Boot項(xiàng)目中使用FreeMarker作為模板引擎的一些常用方法。當(dāng)您使用FreeMarker時(shí),還可以使用一些高級(jí)特性,例如條件語句、迭代器和宏,來更好地控制生成的HTML頁面。
程設(shè)計(jì)是工作流的入口,開發(fā)者可以通過eclipse插件等來設(shè)計(jì)流程,但是用戶并不會(huì)使用。所以可以在線設(shè)計(jì)的流程才是我們想要的,幸好activiti提供了在線設(shè)計(jì)功能,我們只需要把它集成到我們項(xiàng)目中就行了。
最終效果
image.png
集成Actviti
添加依賴
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.walle</groupId> <artifactId>activity-service</artifactId> <version>0.0.1-SNAPSHOT</version> <name>activity-service</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-boot-admin.version>2.1.1</spring-boot-admin.version> <spring-cloud.version>Greenwich.RC2</spring-cloud.version> <activiti.version>5.22.0</activiti.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <!-- Activiti 啟動(dòng)器 --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring-boot-starter-basic</artifactId> <version>${activiti.version}</version> </dependency> <!-- Activiti 流程圖 --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-diagram-rest</artifactId> <version>${activiti.version}</version> </dependency> <!-- Activiti 在線設(shè)計(jì) --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-modeler</artifactId> <version>${activiti.version}</version> </dependency> <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-client</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.walle</groupId> <artifactId>common-service</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!-- swagger2 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.8.0</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-dependencies</artifactId> <version>${spring-boot-admin.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> </repositories> </project>
下載Activiti源碼包
下載地址:https://www.activiti.org/get-started
解壓下載的源碼包后我們看到目錄結(jié)構(gòu)如下
創(chuàng)建數(shù)據(jù)庫
在activiti-5.22.0/database/create 文件夾中找到對(duì)應(yīng)數(shù)據(jù)庫的sql文件 然后創(chuàng)建相關(guān)數(shù)據(jù)庫。
另外,為了方便管理模型,我們才創(chuàng)建業(yè)務(wù)表來管理模型SQL如下
CREATE TABLE `ts_business_define` ( `business_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵', `business_code` varchar(100) DEFAULT NULL COMMENT '業(yè)務(wù)代碼', `business_name` varchar(255) DEFAULT NULL COMMENT '業(yè)務(wù)名稱', `proc_def_id` varchar(64) DEFAULT NULL COMMENT '流程定義ID', `model_id` varchar(64) DEFAULT NULL COMMENT '模型ID', `delete_status` int(11) DEFAULT '0' COMMENT '刪除標(biāo)記0=正常1=已刪除', `create_by` bigint(20) DEFAULT '0' COMMENT '創(chuàng)建人', `create_byname` varchar(50) DEFAULT '0' COMMENT '創(chuàng)建人姓名', `create_time` datetime DEFAULT NULL COMMENT '創(chuàng)建時(shí)間', `modify_by` bigint(20) DEFAULT NULL COMMENT '修改人', `modify_byname` varchar(50) DEFAULT NULL COMMENT '修改人姓名', `modify_time` datetime DEFAULT NULL COMMENT '修改時(shí)間', PRIMARY KEY (`business_id`) ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;
導(dǎo)入靜態(tài)文件
將activiti-5.22.0/war/activiti-explorer.war解壓
將文件夾內(nèi) diagram-viewer,editor-app,modeler.html拷貝到項(xiàng)目中resource/public目錄下如圖
這里需要修改editor-app/app-cfg.js 來設(shè)置項(xiàng)目跟路徑 我們?cè)O(shè)置為空就可以
ACTIVITI.CONFIG = {
// 'contextRoot' : '/activiti-explorer/service',
'contextRoot' : '',
};
導(dǎo)入模型相關(guān)操作Controller
解壓activiti-5.22.0\libs\activiti-modeler-5.22.0-sources.jar,將StencilsetRestResource.java,
ModelEditorJsonRestResource.java,ModelSaveRestResource.java三個(gè)文件拷貝到controller目錄
下載漢化文件
漢化文件,下載文件并放在resource目錄下
禁用登錄驗(yàn)證
Activiti中自動(dòng)集成了security的權(quán)限驗(yàn)證,當(dāng)我們?cè)L問接口的時(shí)候會(huì)彈出登錄界面,所以我們需要禁用掉登錄驗(yàn)證
在啟動(dòng)類中添加注解
@SpringBootApplication @EnableAutoConfiguration(exclude = { org.activiti.spring.boot.SecurityAutoConfiguration.class, org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class }) public class ActivityServiceApplication { public static void main(String[] args) { SpringApplication.run(ActivityServiceApplication.class, args); } }
創(chuàng)建模型
到此為止,我們的集成工作就基本完成了,我們可以通過瀏覽器訪問
就可以新建一個(gè)模型了如圖
模型管理
通過以上集成我們可以創(chuàng)建一個(gè)新的模型,然后我們會(huì)獲取到一個(gè)模型ID 然后根據(jù)ID我們可以部署流程之類,現(xiàn)在我們通過一些簡單的改造,來實(shí)現(xiàn)頁面上對(duì)模型的操作和部署,并且和我們的業(yè)務(wù)關(guān)聯(lián)起來。
業(yè)務(wù)關(guān)聯(lián)模型
我們可以看到,這里需要一個(gè)模型ID的參數(shù),我們可以把模型ID和業(yè)務(wù)定義關(guān)聯(lián)起來,代碼如下
@Autowired private RepositoryService repositoryService; @Autowired private BusinessDefineService businessDefineService; @PostMapping("getModelId") public ResultResponse getModel(Long businessId, HttpServletRequest request, HttpServletResponse response) { try { BusinessDefine businessDefine = businessDefineService.getById(businessId); String modelId = businessDefine.getModelId(); if (StringUtils.isBlank(modelId)) { modelId = createModel(businessId); } return ResultResponse.ofSuccess(modelId); } catch (Exception e) { log.error("",e); return ResultResponse.ofError(e.getMessage()); } } public String createModel(Long businessId) { try { String modelName = "modelName"; String modelKey = "modelKey"; String description = "description"; ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); RepositoryService repositoryService = processEngine.getRepositoryService(); ObjectMapper objectMapper = new ObjectMapper(); ObjectNode editorNode = objectMapper.createObjectNode(); editorNode.put("id", "canvas"); editorNode.put("resourceId", "canvas"); ObjectNode stencilSetNode = objectMapper.createObjectNode(); stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#"); editorNode.put("stencilset", stencilSetNode); Model modelData = repositoryService.newModel(); ObjectNode modelObjectNode = objectMapper.createObjectNode(); modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, modelName); modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1); modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description); modelData.setMetaInfo(modelObjectNode.toString()); modelData.setName(modelName); modelData.setKey(modelKey); //保存模型 repositoryService.saveModel(modelData); repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8")); BusinessDefine businessDefine = businessDefineService.getById(businessId); businessDefine.setModelId(modelData.getId()); businessDefineService.update(businessDefine); return modelData.getId(); } catch (Exception e) { return null; } }
這里我們進(jìn)行了一下判斷,業(yè)務(wù)是否關(guān)聯(lián)了模型,如果關(guān)聯(lián)返回模型ID 如果沒關(guān)聯(lián),創(chuàng)建一個(gè)新的模型并返回Id并關(guān)聯(lián)業(yè)務(wù)
部署模型
通過業(yè)務(wù)定義獲取模型,然后部署模型
/**
* 根據(jù)Model部署流程
*/
@PostMapping(value = "deploy")
public ResultResponse deploy(Long businessId) {
try {
BusinessDefine businessDefine = businessDefineService.getById(businessId);
if (StringUtils.isBlank(businessDefine.getModelId())) {
throw new SystemException("請(qǐng)先設(shè)計(jì)模型");
}
Model modelData = repositoryService.getModel(businessDefine.getModelId());
ObjectNode modelNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
byte[] bpmnBytes = null;
BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
bpmnBytes = new BpmnXMLConverter().convertToXML(model);
String processName = modelData.getName() + ".bpmn20.xml";
Deployment deployment = repositoryService.createDeployment().name(modelData.getName()).addString(processName, new String(bpmnBytes, "UTF-8")).deploy();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
businessDefine.setProcDefId(processDefinition.getId());
businessDefineService.update(businessDefine);
return ResultResponse.ofSuccess();
} catch (Exception e) {
log.error("部署模型", e.getMessage(), e);
return ResultResponse.ofError(e.getMessage());
}
}
導(dǎo)出流程
/** * 導(dǎo)出model的xml文件 */ @GetMapping(value = "export") public void export(Long businessId, HttpServletResponse response) { try { BusinessDefine businessDefine = businessDefineService.getById(businessId); if (StringUtils.isBlank(businessDefine.getModelId())) { throw new SystemException("請(qǐng)先設(shè)計(jì)模型"); } String modelId = businessDefine.getModelId(); Model modelData = repositoryService.getModel(modelId); BpmnJsonConverter jsonConverter = new BpmnJsonConverter(); JsonNode editorNode = new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId())); BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode); BpmnXMLConverter xmlConverter = new BpmnXMLConverter(); byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel); ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes); OutputStream outputStream = response.getOutputStream(); IOUtils.copy(in, outputStream); String filename = bpmnModel.getMainProcess().getId() + ".bpmn.xml"; response.setHeader("content-type", "application/octet-stream"); response.setContentType("application/octet-stream;charset=UTF-8"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename,"utf-8") ); outputStream.flush(); outputStream.close(); } catch (Exception e) { log.error("導(dǎo)出model的xml文件失敗:{}",e.getMessage(), e); } }
導(dǎo)入流程
通過xml導(dǎo)入流程會(huì)生成流程定義,但是不會(huì)創(chuàng)建模型,所以我們要通過流程定義創(chuàng)建模型
導(dǎo)入流程定義
@PostMapping("import") public ResultResponse importXml(@RequestParam("file") MultipartFile file,Long businessId) { try { BusinessDefine businessDefine = businessDefineService.getById(businessId); InputStream fileInputStream = file.getInputStream(); Deployment deployment = repositoryService.createDeployment() .addInputStream(businessDefine.getBusinessName() +".bpmn", fileInputStream) .deploy(); ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult(); String modelId = changeProcessToModel(processDefinition); businessDefine.setProcDefId(processDefinition.getId()); businessDefine.setModelId(modelId); businessDefineService.update(businessDefine); return ResultResponse.ofSuccess(); } catch (Exception e) { log.error("導(dǎo)入流程定義失敗:{}",e.getMessage(),e); return ResultResponse.ofError(e.getMessage()); } }
通過流程生成模型
/** * 流程轉(zhuǎn)化為可編輯模型 * * @param processDefinition */ public String changeProcessToModel(ProcessDefinition processDefinition) { Model modelData = repositoryService.newModel(); ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 初始化Model ObjectMapper objectMapper = new ObjectMapper(); ObjectNode modelObjectNode = objectMapper.createObjectNode(); modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, processDefinition.getName()); modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1); modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, processDefinition.getDescription()); modelData.setMetaInfo(modelObjectNode.toString()); modelData.setName(processDefinition.getName()); modelData.setKey(processDefinition.getKey()); // 保存模型 repositoryService.saveModel(modelData); String deploymentId = processDefinition.getDeploymentId(); String processDefineResourceName = null; // 通過deploymentId取得某個(gè)部署的資源的名稱 List<String> resourceNames = processEngine.getRepositoryService().getDeploymentResourceNames(deploymentId); if (resourceNames != null && resourceNames.size() > 0) { for (String temp : resourceNames) { if (temp.indexOf(".bpmn") > 0) { processDefineResourceName = temp; } } } InputStream bpmnStream = processEngine.getRepositoryService().getResourceAsStream(deploymentId, processDefineResourceName); createModelByInputStream(bpmnStream, modelData.getId()); return modelData.getId(); } public void createModelByInputStream(InputStream bpmnStream, String ModelID) { XMLInputFactory xif; InputStreamReader in = null; XMLStreamReader xtr = null; try { xif = XMLInputFactory.newFactory(); in = new InputStreamReader(bpmnStream, "UTF-8"); xtr = xif.createXMLStreamReader(in); BpmnModel bpmnModel = (new BpmnXMLConverter()).convertToBpmnModel(xtr); ObjectNode modelNode = new BpmnJsonConverter().convertToJson(bpmnModel); repositoryService.addModelEditorSource(ModelID, modelNode.toString().getBytes("UTF-8")); } catch (XMLStreamException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } finally { if (xtr != null) { try { xtr.close(); } catch (XMLStreamException e) { e.printStackTrace(); } } if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if (bpmnStream != null) { try { bpmnStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } 完!
歡迎工作一到五年的Java工程師朋友們加入Java程序員開發(fā): 854393687
群內(nèi)提供免費(fèi)的Java架構(gòu)學(xué)習(xí)資料(里面有高可用、高并發(fā)、高性能及分布式、Jvm性能調(diào)優(yōu)、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個(gè)知識(shí)點(diǎn)的架構(gòu)資料)合理利用自己每一分每一秒的時(shí)間來學(xué)習(xí)提升自己,不要再用"沒有時(shí)間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個(gè)交代!
HTML Webpack Plugin這是一個(gè)webpack插件,它簡化了HTML文件的創(chuàng)建,以服務(wù)于你的webpack bundle。這對(duì)于在文件名中包含哈希的webpack包特別有用,因?yàn)槲募麜?huì)改變每次編譯。您可以讓插件為您生成一個(gè)HTML文件,或者使用lodash模板提供您自己的模板,或者使用您自己的加載器。
針對(duì)webpack的版本,需要安裝對(duì)應(yīng)不同的版本。
webpack4
npm i --save-dev html-webpack-plugin@4
webpack5
npm i --save-dev html-webpack-plugin
這個(gè)插件會(huì)為你生成一個(gè)HTML5文件,其中包含了使用script標(biāo)簽的所有webpack的bundle。
只需將插件添加到webpack配置中,如下所示:
const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
entry: "./src/index.js",
output: {
filename:"index_bundle.js",
path: path.resolve(__dirname,"dist")
},
plugins: [
new HtmlWebpackPlugin()
]
}
這將生成一個(gè)包含以下內(nèi)容的文件dist/index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Webpack App</title>
</head>
<body>
<script src="index_bundle.js"></script>
</body>
</html>
如果您有多個(gè)webpack入口點(diǎn),它們都將與script標(biāo)簽一起包含在生成的HTML中。
如果你在webpack的輸出中有任何CSS資產(chǎn)(例如,用mini-css-extract-plugin提取的CSS),那么這些將包含在HTML頭部的標(biāo)簽中。
如果你有使用它的插件,html-webpack-plugin應(yīng)該在任何集成插件之前。
你可以傳遞一個(gè)配置選項(xiàng)到html-webpack-plugin。允許的值如下:
類型:String
默認(rèn)值:Webpack App
描述:要用于生成的HTML文檔的標(biāo)題。
類型:String或Function
默認(rèn)值:index.html
描述:要寫入HTML的文件的文件名。默認(rèn)為index.html。您也可以在這里指定一個(gè)子目錄(例如:assets/admin.html)。占位符[name]將被條目名稱替換。也可以是一個(gè)函數(shù),例如(entryName) => entryName + '.html'。
類型:String
默認(rèn)值:空
描述:默認(rèn)情況下,它將使用src/index.ejs(如果存在的話)。
類型:string|Function|false
默認(rèn)值:false
描述:可以用來代替模板提供一個(gè)內(nèi)聯(lián)模板。
類型:Boolean|Object|Function
默認(rèn)值:false
描述:允許覆蓋模板中使用的參數(shù)。
類型:Boolean|String
默認(rèn)值:true
描述:true || 'head' || 'body' || false將所有資產(chǎn)注入到給定的模板或templateContent中。當(dāng)傳遞'body'時(shí),所有javascript資源將被放置在body元素的底部。'head'將把腳本放置在head元素中。設(shè)置為true時(shí),將根據(jù)scriptLoading選項(xiàng),決定是把腳本添加到head還是body中。使用false禁用自動(dòng)注入。
類型:String|'auto'
默認(rèn)值:auto
描述:publicPath屬性值用于script和link 標(biāo)簽。
類型:blocking|defer
默認(rèn)值:defer
描述:現(xiàn)代瀏覽器支持非阻塞javascript加載(“defer”),以提高頁面啟動(dòng)性能。
類型:String
默認(rèn)值:空
描述:將給定的圖標(biāo)路徑添加到輸出的HTML中。
類型:Object
默認(rèn)值:{}
描述:允許注入meta標(biāo)簽。例如:meta: {viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no'}。
類型:Object|String|false
默認(rèn)值:false
描述:注入一個(gè)base標(biāo)簽。如base:“https://example.com/path/page.html
類型:Boolean|Object
默認(rèn)值:如果mode為'production'則為true,否則為false
描述:控制是否以及以何種方式壓縮輸出。
類型:Boolean
默認(rèn)值:false
描述:如果為true,則附加一個(gè)唯一的webpack編譯哈希到所有包含的腳本和CSS文件。這對(duì)于緩存銷毀是很有用的
類型:Boolean
默認(rèn)值:true
描述:只有當(dāng)文件被更改時(shí),才會(huì)刪除它。
類型:Boolean
默認(rèn)值:true
描述:錯(cuò)誤的詳細(xì)信息將寫入HTML頁面。
類型:?
默認(rèn)值:?
描述:只允許添加一些chunk(例如:只添加unit-test 的chunk)
類型:String|Function
默認(rèn)值:auto
描述:允許控制塊在包含到HTML之前應(yīng)該如何排序。允許的值是'none' | 'auto' | 'manual' | {Function}。
類型:Array.<string>
默認(rèn)值:空
描述:允許你跳過一些chunk(例如不添加unit-test 的chunk)。
類型:Boolean
默認(rèn)值:false
描述:如果為true,則將link標(biāo)簽呈現(xiàn)為自動(dòng)關(guān)閉(XHTML兼容)
下面是一個(gè)webpack配置示例,演示了如何使用這些選項(xiàng):
{
entry: 'index.js',
output: {
path: __dirname + '/dist',
filename: 'index_bundle.js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'My App',
filename: 'assets/admin.html'
})
]
}
要生成多個(gè)HTML文件,請(qǐng)?jiān)诓寮?shù)組中多次聲明插件。
配置示例:
{
entry: 'index.js',
output: {
path: __dirname + '/dist',
filename: 'index_bundle.js'
},
plugins: [
new HtmlWebpackPlugin(), // Generates default index.html
new HtmlWebpackPlugin({ // Also generate a test.html
filename: 'test.html',
template: 'src/assets/test.html'
})
]
}
如果默認(rèn)生成的HTML不能滿足您的需要,您可以提供自己的模板。最簡單的方法是使用template選項(xiàng)并傳遞一個(gè)定制的HTML文件。html-webpack-plugin會(huì)自動(dòng)將所有必需的CSS, JS, manifest和favicon文件注入到標(biāo)記中。
配置文件的部分內(nèi)容:
plugins: [
new HtmlWebpackPlugin({
title: 'Custom template',
// Load a custom template (lodash by default)
template: 'index.html'
})
]
模板文件index.html的內(nèi)容:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
</body>
</html>
如果您已經(jīng)有一個(gè)模板加載器,您可以使用它來解析模板。請(qǐng)注意,如果您指定了html加載器并使用.html文件作為模板,也會(huì)發(fā)生這種情況。
module: {
loaders: [
{ test: /\.hbs$/, loader: "handlebars-loader" }
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'Custom template using Handlebars',
template: 'index.hbs'
})
]
您可以使用現(xiàn)成的lodash語法。如果inject特性不適合你的需要,而你又想完全控制資產(chǎn)的位置,可以使用html-webpack-template項(xiàng)目的默認(rèn)模板作為你自己編寫模板的起點(diǎn)。
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。