整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

每日分享- springboot 微服务项目如何集成 html

pring Boot 微服务项目通常是通过 REST API 来提供服务的,而不是直接集成 HTML 页面。不过,今天看到有小伙伴在咨询如何在 Spring Boot 项目中集成 HTML 页面,简单整理了一下,可以采用以下常用的方法:

  1. Thymeleaf:Thymeleaf 是一款用于在 web 和独立环境中创建可扩展的 XML/HTML/文本模板的 Java 模板引擎。它可以轻松地与 Spring Boot 集成,使用简单,支持模板继承和表达式语言等功能。
  2. FreeMarker:FreeMarker 是一款基于模板的视图渲染引擎,支持动态 HTML、XML、JSON、JavaScript、CSS 等文件的生成。它也可以轻松地与 Spring Boot 集成,使用简单,支持模板继承和自定义指令等功能。
  3. JSP:JSP 是一种基于 Java 技术的动态网页开发技术,可以方便地嵌入 Java 代码,并生成 HTML 页面。它也可以与 Spring Boot 集成,但需要额外配置一些依赖和插件。

举例来说,如果你选择使用 Thymeleaf,可以按照以下步骤来实现:

--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 目录下创建 HTML 模板文件,并使用 Thymeleaf 标签进行动态数据绑定和条件渲染等操作。

例如,以下是一个简单的 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 应用程序的控制器中,使用 @GetMapping 注解定义一个返回 ModelAndView 对象的请求处理方法,并将模板文件名和动态数据传递给 ModelAndView 对象。

例如,以下是一个简单的控制器类 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 页面了。


再举一个FreeMarker的例子来简单说一下:

当使用Spring Boot构建Web应用程序时,可以使用FreeMarker作为模板引擎来渲染HTML页面。FreeMarker是一个开源的Java模板引擎,它允许您通过定义模板来生成HTML等文档。下面是在Spring Boot项目中集成FreeMarker的一些常用方法:

--1 添加依赖:在项目的pom.xml文件中添加FreeMarker的依赖项:

<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 创建模板文件:在src/main/resources/templates目录下创建.ftl文件,该文件将用于渲染HTML页面。在模板文件中,您可以使用FreeMarker的模板语言来定义HTML页面的内容。

例如,以下是一个简单的模板文件,它将渲染一个包含“Hello World”的HTML页面:

<!DOCTYPE html>
<html>
<head>
    <title>Hello World</title>
</head>
<body>
    <h1>${message}</h1>
</body>
</html>

在上面的模板中,${message}将被替换为实际的值。您可以在Java代码中使用模型来设置这个值。

--4 创建控制器:在Spring Boot应用程序中创建一个控制器,以处理HTTP请求并返回模板的名称和模型。以下是一个示例控制器:

@Controller
public class HomeController {
    @GetMapping("/")
    public String home(Model model) {
        model.addAttribute("message", "Hello World!");
        return "home";
    }
}

在上面的示例中,控制器返回了“home”字符串,这将作为模板文件的名称。它还将模型添加到视图中,该模型包含名为“message”的属性和“Hello World!”的值。

这是在Spring Boot项目中使用FreeMarker作为模板引擎的一些常用方法。当您使用FreeMarker时,还可以使用一些高级特性,例如条件语句、迭代器和宏,来更好地控制生成的HTML页面。

程设计是工作流的入口,开发者可以通过eclipse插件等来设计流程,但是用户并不会使用。所以可以在线设计的流程才是我们想要的,幸好activiti提供了在线设计功能,我们只需要把它集成到我们项目中就行了。

最终效果

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 启动器 -->
 <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 在线设计 -->
 <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

解压下载的源码包后我们看到目录结构如下

创建数据库

在activiti-5.22.0/database/create 文件夹中找到对应数据库的sql文件 然后创建相关数据库。

另外,为了方便管理模型,我们才创建业务表来管理模型SQL如下

CREATE TABLE `ts_business_define` (
 `business_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
 `business_code` varchar(100) DEFAULT NULL COMMENT '业务代码',
 `business_name` varchar(255) DEFAULT NULL COMMENT '业务名称',
 `proc_def_id` varchar(64) DEFAULT NULL COMMENT '流程定义ID',
 `model_id` varchar(64) DEFAULT NULL COMMENT '模型ID',
 `delete_status` int(11) DEFAULT '0' COMMENT '删除标记0=正常1=已删除',
 `create_by` bigint(20) DEFAULT '0' COMMENT '创建人',
 `create_byname` varchar(50) DEFAULT '0' COMMENT '创建人姓名',
 `create_time` datetime DEFAULT NULL COMMENT '创建时间',
 `modify_by` bigint(20) DEFAULT NULL COMMENT '修改人',
 `modify_byname` varchar(50) DEFAULT NULL COMMENT '修改人姓名',
 `modify_time` datetime DEFAULT NULL COMMENT '修改时间',
 PRIMARY KEY (`business_id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;

导入静态文件

将activiti-5.22.0/war/activiti-explorer.war解压

将文件夹内 diagram-viewer,editor-app,modeler.html拷贝到项目中resource/public目录下如图



这里需要修改editor-app/app-cfg.js 来设置项目跟路径 我们设置为空就可以

ACTIVITI.CONFIG = {

// 'contextRoot' : '/activiti-explorer/service',

'contextRoot' : '',

};

导入模型相关操作Controller

解压activiti-5.22.0\libs\activiti-modeler-5.22.0-sources.jar,将StencilsetRestResource.java,

ModelEditorJsonRestResource.java,ModelSaveRestResource.java三个文件拷贝到controller目录

下载汉化文件

汉化文件,下载文件并放在resource目录下

禁用登录验证

Activiti中自动集成了security的权限验证,当我们访问接口的时候会弹出登录界面,所以我们需要禁用掉登录验证

在启动类中添加注解

@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);
 }
}

创建模型

到此为止,我们的集成工作就基本完成了,我们可以通过浏览器访问

就可以新建一个模型了如图



模型管理

通过以上集成我们可以创建一个新的模型,然后我们会获取到一个模型ID 然后根据ID我们可以部署流程之类,现在我们通过一些简单的改造,来实现页面上对模型的操作和部署,并且和我们的业务关联起来。

业务关联模型

我们可以看到,这里需要一个模型ID的参数,我们可以把模型ID和业务定义关联起来,代码如下

 @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;
 }
 }

这里我们进行了一下判断,业务是否关联了模型,如果关联返回模型ID 如果没关联,创建一个新的模型并返回Id并关联业务

部署模型

通过业务定义获取模型,然后部署模型

/**

* 根据Model部署流程

*/

@PostMapping(value = "deploy")

public ResultResponse deploy(Long businessId) {

try {

BusinessDefine businessDefine = businessDefineService.getById(businessId);

if (StringUtils.isBlank(businessDefine.getModelId())) {

throw new SystemException("请先设计模型");

}

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());

}

}

导出流程

 /**
 * 导出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("请先设计模型");
 }
 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("导出model的xml文件失败:{}",e.getMessage(), e);
 }
 }

导入流程

通过xml导入流程会生成流程定义,但是不会创建模型,所以我们要通过流程定义创建模型

导入流程定义

 @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("导入流程定义失败:{}",e.getMessage(),e);
 return ResultResponse.ofError(e.getMessage());
 }
 }

通过流程生成模型

 /**
 * 流程转化为可编辑模型
 *
 * @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取得某个部署的资源的名称
 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程序员开发: 854393687

群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

HTML Webpack Plugin这是一个webpack插件,它简化了HTML文件的创建,以服务于你的webpack bundle。这对于在文件名中包含哈希的webpack包特别有用,因为文件名会改变每次编译。您可以让插件为您生成一个HTML文件,或者使用lodash模板提供您自己的模板,或者使用您自己的加载器。

安装

针对webpack的版本,需要安装对应不同的版本。

webpack4

npm i --save-dev html-webpack-plugin@4

webpack5

  npm i --save-dev html-webpack-plugin

使用

这个插件会为你生成一个HTML5文件,其中包含了使用script标签的所有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()
    ]
}

这将生成一个包含以下内容的文件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>

如果您有多个webpack入口点,它们都将与script标签一起包含在生成的HTML中。

如果你在webpack的输出中有任何CSS资产(例如,用mini-css-extract-plugin提取的CSS),那么这些将包含在HTML头部的标签中。

如果你有使用它的插件,html-webpack-plugin应该在任何集成插件之前。

选项

你可以传递一个配置选项到html-webpack-plugin。允许的值如下:

  • title

类型:String

默认值:Webpack App

描述:要用于生成的HTML文档的标题。

  • filename

类型:String或Function

默认值:index.html

描述:要写入HTML的文件的文件名。默认为index.html。您也可以在这里指定一个子目录(例如:assets/admin.html)。占位符[name]将被条目名称替换。也可以是一个函数,例如(entryName) => entryName + '.html'。

  • template

类型:String

默认值:空

描述:默认情况下,它将使用src/index.ejs(如果存在的话)。

  • templateContent

类型:string|Function|false

默认值:false

描述:可以用来代替模板提供一个内联模板。

  • templateParameters

类型:Boolean|Object|Function

默认值:false

描述:允许覆盖模板中使用的参数。

  • inject

类型:Boolean|String

默认值:true

描述:true || 'head' || 'body' || false将所有资产注入到给定的模板或templateContent中。当传递'body'时,所有javascript资源将被放置在body元素的底部。'head'将把脚本放置在head元素中。设置为true时,将根据scriptLoading选项,决定是把脚本添加到head还是body中。使用false禁用自动注入。

  • publicPath

类型:String|'auto'

默认值:auto

描述:publicPath属性值用于script和link 标签。

  • scriptLoading

类型:blocking|defer

默认值:defer

描述:现代浏览器支持非阻塞javascript加载(“defer”),以提高页面启动性能。

  • favicon

类型:String

默认值:空

描述:将给定的图标路径添加到输出的HTML中。

  • meta

类型:Object

默认值:{}

描述:允许注入meta标签。例如:meta: {viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no'}。

  • base

类型:Object|String|false

默认值:false

描述:注入一个base标签。如base:“https://example.com/path/page.html

  • minify

类型:Boolean|Object

默认值:如果mode为'production'则为true,否则为false

描述:控制是否以及以何种方式压缩输出。

  • hash

类型:Boolean

默认值:false

描述:如果为true,则附加一个唯一的webpack编译哈希到所有包含的脚本和CSS文件。这对于缓存销毁是很有用的

  • cache

类型:Boolean

默认值:true

描述:只有当文件被更改时,才会删除它。

  • showErrors

类型:Boolean

默认值:true

描述:错误的详细信息将写入HTML页面。

  • chunks

类型:?

默认值:?

描述:只允许添加一些chunk(例如:只添加unit-test 的chunk)

  • chunksSortMode

类型:String|Function

默认值:auto

描述:允许控制块在包含到HTML之前应该如何排序。允许的值是'none' | 'auto' | 'manual' | {Function}。

  • excludeChunks

类型:Array.<string>

默认值:空

描述:允许你跳过一些chunk(例如不添加unit-test 的chunk)。

  • xhtml

类型:Boolean

默认值:false

描述:如果为true,则将link标签呈现为自动关闭(XHTML兼容)

下面是一个webpack配置示例,演示了如何使用这些选项:

{
  entry: 'index.js',
  output: {
    path: __dirname + '/dist',
    filename: 'index_bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'My App',
      filename: 'assets/admin.html'
    })
  ]
}

生成多个HTML文件

要生成多个HTML文件,请在插件数组中多次声明插件。

配置示例:

{
  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'
    })
  ]
}

编写模板

如果默认生成的HTML不能满足您的需要,您可以提供自己的模板。最简单的方法是使用template选项并传递一个定制的HTML文件。html-webpack-plugin会自动将所有必需的CSS, JS, manifest和favicon文件注入到标记中。

配置文件的部分内容:

plugins: [
  new HtmlWebpackPlugin({
    title: 'Custom template',
    // Load a custom template (lodash by default)
    template: 'index.html'
  })
]

模板文件index.html的内容:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
  </body>
</html>

如果您已经有一个模板加载器,您可以使用它来解析模板。请注意,如果您指定了html加载器并使用.html文件作为模板,也会发生这种情况。

module: {
  loaders: [
    { test: /\.hbs$/, loader: "handlebars-loader" }
  ]
},
plugins: [
  new HtmlWebpackPlugin({
    title: 'Custom template using Handlebars',
    template: 'index.hbs'
  })
]

您可以使用现成的lodash语法。如果inject特性不适合你的需要,而你又想完全控制资产的位置,可以使用html-webpack-template项目的默认模板作为你自己编写模板的起点。