摘要:和类似的预处理器还有等。的用处非常多,包括给自动加前缀使用下一代语法等,目前越来越多的人开始用它,它很可能会成为预处理器的最终赢家。
webpack实战
查看所有文档页面:全栈开发,获取更多信息。快马加鞭,加班加点,终于把这个文档整理出来了,顺便深入地学习一番,巩固知识,就是太累人,影响睡眠时间和质量。极客就是想要把事情做到极致,开始了就必须到达终点。
原文链接:webpack实战,原文广告模态框遮挡,阅读体验不好,所以整理成本文,方便查找。
本章教你如何用 Webpack 去解决实际项目中常见的场景。
按照不同场景划分成以下几类:
使用新语言来开发项目:
使用 ES6 语言
使用 TypeScript 语言
使用 Flow 检查器
使用 SCSS 语言
使用 PostCSS
使用新框架来开发项目:
使用 React 框架
使用 Vue 框架
使用 Angular2 框架
用 Webpack 构建单页应用:
为单页应用生成 HTML
管理多个单页应用
用 Webpack 构建不同运行环境的项目:
构建同构应用
构建 Electron 应用
构建 Npm 模块
构建离线应用
Webpack 结合其它工具搭配使用,各取所长:
搭配 Npm Script
检查代码
通过 Node.js API 启动 Webpack
使用 Webpack Dev Middleware
用 Webpack 加载特殊类型的资源:
加载图片
加载SVG
加载 Source Map
使用 TypeScript 语言由于本文不推荐使用TypeScript,ES6就足够完成大部分任务。原文链接:使用 TypeScript 语言
使用 Angular2 框架Angular2不在我的技术栈范围,所以这一章不加入,有兴趣的查看原文:使用 Angular2 框架
使用ES6语言通常我们需要把采用 ES6 编写的代码转换成目前已经支持良好的 ES5 代码,这包含2件事:
把新的 ES6 语法用 ES5 实现,例如 ES6 的 class 语法用 ES5 的 prototype 实现。
给新的 API 注入 polyfill ,例如使用新的 fetch API 时注入对应的 polyfill 后才能让低端浏览器正常运行。
BabelBabel 可以方便的完成以上2件事。
Babel 是一个 JavaScript 编译器,能将 ES6 代码转为 ES5 代码,让你使用最新的语言特性而不用担心兼容性问题,并且可以通过插件机制根据需求灵活的扩展。
在 Babel 执行编译的过程中,会从项目根目录下的 .babelrc 文件读取配置。.babelrc 是一个 JSON 格式的文件,内容大致如下:
{ "plugins": [ [ "transform-runtime", { "polyfill": false } ] ], "presets": [ [ "es2015", { "modules": false } ], "stage-2", "react" ] }Plugins
plugins 属性告诉 Babel 要使用哪些插件,插件可以控制如何转换代码。
以上配置文件里的 transform-runtime 对应的插件全名叫做 babel-plugin-transform-runtime,即在前面加上了 babel-plugin-,要让 Babel 正常运行我们必须先安装它:
npm i -D babel-plugin-transform-runtime
babel-plugin-transform-runtime 是 Babel 官方提供的一个插件,作用是减少冗余代码。
Babel 在把 ES6 代码转换成 ES5 代码时通常需要一些 ES5 写的辅助函数来完成新语法的实现,例如在转换 class extent 语法时会在转换后的 ES5 代码里注入 _extent 辅助函数用于实现继承:
function _extent(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }
这会导致每个使用了 class extent 语法的文件都被注入重复的 _extent 辅助函数代码,babel-plugin-transform-runtime 的作用在于不把辅助函数内容注入到文件里,而是注入一条导入语句:
var _extent = require("babel-runtime/helpers/_extent");
这样能减小 Babel 编译出来的代码的文件大小。
同时需要注意的是由于 babel-plugin-transform-runtime 注入了 require("babel-runtime/helpers/_extent") 语句到编译后的代码里,需要安装 babel-runtime 依赖到你的项目后,代码才能正常运行。 也就是说 babel-plugin-transform-runtime 和 babel-runtime 需要配套使用,使用了 babel-plugin-transform-runtime 后一定需要 babel-runtime。
Presetspresets 属性告诉 Babel 要转换的源码使用了哪些新的语法特性,一个 Presets 对一组新语法特性提供支持,多个 Presets 可以叠加。
Presets 其实是一组 Plugins 的集合,每一个 Plugin 完成一个新语法的转换工作。Presets 是按照 ECMAScript 草案来组织的,通常可以分为以下三大类:
已经被写入 ECMAScript 标准里的特性,由于之前每年都有新特性被加入到标准里;
env 包含当前所有 ECMAScript 标准里的最新特性。
被社区提出来的但还未被写入 ECMAScript 标准里特性,这其中又分为以下四种:
stage0 只是一个美好激进的想法,有 Babel 插件实现了对这些特性的支持,但是不确定是否会被定为标准;
stage1 值得被纳入标准的特性;
stage2 该特性规范已经被起草,将会被纳入标准里;
stage3 该特性规范已经定稿,各大浏览器厂商和 Node.js 社区开始着手实现;
stage4 在接下来的一年将会加入到标准里去。
为了支持一些特定应用场景下的语法,和 ECMAScript 标准没有关系,例如 babel-preset-react 是为了支持 React 开发中的 JSX 语法。
在实际应用中,你需要根据项目源码所使用的语法去安装对应的 Plugins 或 Presets。
接入 Babel由于 Babel 所做的事情是转换代码,所以应该通过 Loader 去接入 Babel,Webpack 配置如下:
module.exports = { module: { rules: [ { test: /.js$/, use: ["babel-loader"], }, ] }, // 输出 source-map 方便直接调试 ES6 源码 devtool: "source-map" };
配置命中了项目目录下所有的 JavaScript 文件,通过 babel-loader 去调用 Babel 完成转换工作。 在重新执行构建前,需要先安装新引入的依赖:
# Webpack 接入 Babel 必须依赖的模块 npm i -D babel-core babel-loader # 根据你的需求选择不同的 Plugins 或 Presets npm i -D babel-preset-env使用SCSS语言
SCSS 可以让你用更灵活的方式写 CSS。 它是一种 CSS 预处理器,语法和 CSS 相似,但加入了变量、逻辑等编程元素,代码类似这样:
$blue: #1875e7; div { color: $blue; }
SCSS 又叫 SASS,区别在于 SASS 语法类似 Ruby,而 SCSS 语法类似 CSS,对于熟悉 CSS 的前端工程师来说会更喜欢 SCSS。
采用 SCSS 去写 CSS 的好处在于可以方便地管理代码,抽离公共的部分,通过逻辑写出更灵活的代码。 和 SCSS 类似的 CSS 预处理器还有 LESS 等。
使用 SCSS 可以提升编码效率,但是必须把 SCSS 源代码编译成可以直接在浏览器环境下运行的 CSS 代码。
node-sass 核心模块是由 C++ 编写,再用 Node.js 封装了一层,以供给其它 Node.js 调用。 node-sass 还支持通过命令行调用,先安装它到全局:
npm i -g node-sass
再执行编译命令:
# 把 main.scss 源文件编译成 main.css node-sass main.scss main.css
你就能在源码同目录下看到编译后的 main.css 文件。
接入 WebpackWebpack 接入 sass-loader 相关配置如下:
module.exports = { module: { rules: [ { // 增加对 SCSS 文件的支持 test: /.scss/, // SCSS 文件的处理顺序为先 sass-loader 再 css-loader 再 style-loader use: ["style-loader", "css-loader", "sass-loader"], }, ] }, };
以上配置通过正则 /.scss/ 匹配所有以 .scss 为后缀的 SCSS 文件,再分别使用3个 Loader 去处理。具体处理流程如下:
通过 sass-loader 把 SCSS 源码转换为 CSS 代码,再把 CSS 代码交给 css-loader 去处理。
css-loader 会找出 CSS 代码中的 @import 和 url() 这样的导入语句,告诉 Webpack 依赖这些资源。同时还支持 CSS Modules、压缩 CSS 等功能。处理完后再把结果交给 style-loader 去处理。
style-loader 会把 CSS 代码转换成字符串后,注入到 JavaScript 代码中去,通过 JavaScript 去给 DOM 增加样式。如果你想把 CSS 代码提取到一个多带带的文件而不是和 JavaScript 混在一起,可以使用1-5 使用Plugin 中介绍过的 ExtractTextPlugin。
由于接入 sass-loader,项目需要安装这些新的依赖:
# 安装 Webpack Loader 依赖 npm i -D sass-loader css-loader style-loader # sass-loader 依赖 node-sass npm i -D node-sass使用Flow检查器
Flow 是一个 Facebook 开源的 JavaScript 静态类型检测器,它是 JavaScript 语言的超集。
你所需要做的就是在需要的地方加上类型检查,例如在两个由不同人开发的模块对接的接口出加上静态类型检查,能在编译阶段就指出部分模块使用不当的问题。 同时 Flow 也能通过类型推断检查出 JavaScript 代码中潜在的 Bug。
Flow 使用效果如下:
// @flow // 静态类型检查 function square1(n: number): number { return n * n; } square1("2"); // Error: square1 需要传入 number 作为参数 // 类型推断检查 function square2(n) { return n * n; // Error: 传入的 string 类型不能做乘法运算 } square2("2");
需要注意的时代码中的第一行 // @flow 告诉 Flow 检查器这个文件需要被检查。使用 Flow
Flow 检测器由高性能跨平台的 OCaml 语言编写,它的可执行文件可以通过:
npm i -D flow-bin
安装,安装完成后通过先配置 Npm Script:
"scripts": { "flow": "flow" }
再通过 npm run flow 去调用 Flow 执行代码检查。
除此之外你还可以通过:
npm i -g flow-bin
把 Flow 安装到全局后,再直接通过 flow 命令去执行代码检查。
安装成功后,在项目根目录下执行 Flow 后,Flow 会遍历出所有需要检查的文件并对其进行检查,输出错误结果到控制台。
采用了 Flow 静态类型语法的 JavaScript 是无法直接在目前已有的 JavaScript 引擎中运行的,要让代码可以运行需要把这些静态类型语法去掉。
// 采用 Flow 的源代码 function foo(one: any, two: number, three?): string {} // 去掉静态类型语法后输出代码 function foo(one, two, three) {}
有两种方式可以做到这点:
flow-remove-types 可多带带使用,速度快。
babel-preset-flow 与 Babel 集成。
集成 Webpack由于使用了 Flow 项目一般都会使用 ES6 语法,所以把 Flow 集成到使用 Webpack 构建的项目里最方便的方法是借助 Babel。
安装 npm i -D babel-preset-flow 依赖到项目。
修改 .babelrc 配置文件,加入 Flow Preset:
"presets": [ ...[], "flow" ]
往源码里加入静态类型后重新构建项目,你会发现采用了 Flow 的源码还是能正常在浏览器中运行。
要明确构建的目的只是为了去除源码中的 Flow 静态类型语法,而代码检查和构建无关。 许多编辑器已经整合 Flow,可以实时在代码中高亮指出 Flow 检查出的问题。使用PostCSS
PostCSS 是一个 CSS 处理工具,和 SCSS 不同的地方在于它通过插件机制可以灵活的扩展其支持的特性,而不是像 SCSS 那样语法是固定的。 PostCSS 的用处非常多,包括给 CSS 自动加前缀、使用下一代 CSS 语法等,目前越来越多的人开始用它,它很可能会成为 CSS 预处理器的最终赢家。
PostCSS 和 CSS 的关系就像 Babel 和 JavaScript 的关系,它们解除了语法上的禁锢,通过插件机制来扩展语言本身,用工程化手段给语言带来了更多的可能性。PostCSS 和 SCSS 的关系就像 Babel 和 TypeScript 的关系,PostCSS 更加灵活、可扩张性强,而 SCSS 内置了大量功能而不能扩展。
给 CSS 自动加前缀,增加各浏览器的兼容性:
/*输入*/ h1 { display: flex; } /*输出*/ h1 { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; }
使用下一代 CSS 语法:
/*输入*/ :root { --red: #d33; } h1 { color: var(--red); } /*输出*/ h1 { color: #d33; }
PostCSS 全部采用 JavaScript 编写,运行在 Node.js 之上,即提供了给 JavaScript 代码调用的模块,也提供了可执行的文件。
在 PostCSS 启动时,会从目录下的 postcss.config.js 文件中读取所需配置,所以需要新建该文件,文件内容大致如下:
module.exports = { plugins: [ // 需要使用的插件列表 require("postcss-cssnext") ] }
其中的 postcss-cssnext 插件可以让你使用下一代 CSS 语法编写代码,再通过 PostCSS 转换成目前的浏览器可识别的 CSS,并且该插件还包含给 CSS 自动加前缀的功能。
目前 Chrome 等现代浏览器已经能完全支持 cssnext 中的所有语法,也就是说按照 cssnext 语法写的 CSS 在不经过转换的情况下也能在浏览器中直接运行。接入 Webpack
虽然使用 PostCSS 后文件后缀还是 .css 但这些文件必须先交给 postcss-loader 处理一遍后再交给 css-loader。
接入 PostCSS 相关的 Webpack 配置如下:
module.exports = { module: { rules: [ { // 使用 PostCSS 处理 CSS 文件 test: /.css/, use: ["style-loader", "css-loader", "postcss-loader"], }, ] }, };
接入 PostCSS 给项目带来了新的依赖需要安装,如下:
# 安装 Webpack Loader 依赖 npm i -D postcss-loader css-loader style-loader # 根据你使用的特性安装对应的 PostCSS 插件依赖 npm i -D postcss-cssnext使用React框架 React 语法特征
使用了 React 项目的代码特征有 JSX 和 Class 语法,例如:
class Button extends Component { render() { returnHello,Webpack
} }
在使用了 React 的项目里 JSX 和 Class 语法并不是必须的,但使用新语法写出的代码看上去更优雅。
其中 JSX 语法是无法在任何现有的 JavaScript 引擎中运行的,所以在构建过程中需要把源码转换成可以运行的代码,例如:
// 原 JSX 语法代码 returnReact 与 BabelHello,Webpack
// 被转换成正常的 JavaScript 代码 return React.createElement("h1", null, "Hello,Webpack")
要在使用 Babel 的项目中接入 React 框架是很简单的,只需要加入 React 所依赖的 Presets babel-preset-react。
通过以下命令:
# 安装 React 基础依赖 npm i -D react react-dom # 安装 babel 完成语法转换所需依赖 npm i -D babel-preset-react
安装新的依赖后,再修改 .babelrc 配置文件加入 React Presets
"presets": [ "react" ],
就完成了一切准备工作。
再修改 main.js 文件如下:
import * as React from "react"; import { Component } from "react"; import { render } from "react-dom"; class Button extends Component { render() { returnHello,Webpack
} } render(, window.document.getElementById("app"));
重新执行构建打开网页你将会发现由 React 渲染出来的 Hello,Webpack。
React 与 TypeScriptTypeScript 相比于 Babel 的优点在于它原生支持 JSX 语法,你不需要重新安装新的依赖,只需修改一行配置。 但 TypeScript 的不同在于:
使用了 JSX 语法的文件后缀必须是 tsx。
由于 React 不是采用 TypeScript 编写的,需要安装 react 和 react-dom 对应的 TypeScript 接口描述模块 @types/react 和 @types/react-dom 后才能通过编译。
修改 TypeScript 编译器配置文件 tsconfig.json 增加对 JSX 语法的支持,如下:
{ "compilerOptions": { "jsx": "react" // 开启 jsx ,支持 React } }
由于 main.js 文件中存在 JSX 语法,再把 main.js 文件重命名为 main.tsx,同时修改文件内容为在上面 React 与 Babel 里所采用的 React 代码。 同时为了让 Webpack 对项目里的 ts 与 tsx 原文件都采用 awesome-typescript-loader 去转换, 需要注意的是 Webpack Loader 配置的 test 选项需要匹配到 tsx 类型的文件,并且 extensions 中也要加上 .tsx,配置如下:
module.exports = { // TS 执行入口文件 entry: "./main", output: { filename: "bundle.js", path: path.resolve(__dirname, "./dist"), }, resolve: { // 先尝试 ts,tsx 后缀的 TypeScript 源码文件 extensions: [".ts", ".tsx", ".js",] }, module: { rules: [ { // 同时匹配 ts,tsx 后缀的 TypeScript 源码文件 test: /.tsx?$/, loader: "awesome-typescript-loader" } ] }, devtool: "source-map",// 输出 Source Map 方便在浏览器里调试 TypeScript 代码 };
通过npm i react react-dom @types/react @types/react-dom安装新的依赖后重启构建,重新打开网页你将会发现由 React 渲染出来的 Hello,Webpack。
使用Vue框架Vue是一个渐进式的 MVVM 框架,相比于 React、Angular 它更灵活轻量。 它不会强制性地内置一些功能和语法,你可以根据自己的需要一点点地添加功能。 虽然采用 Vue 的项目能用可直接运行在浏览器环境里的代码编写,但为了方便编码大多数项目都会采用 Vue 官方的单文件组件的写法去编写项目。
Vue 的单文件组件通过一个类似 HTML 文件的 .vue 文件就能描述清楚一个组件所需的模版、样式、逻辑。
main.js 入口文件:
import Vue from "vue" import App from "./App.vue" new Vue({ el: "#app", render: h => h(App) });
入口文件创建一个 Vue 的根实例,在 ID 为 app 的 DOM 节点上渲染出上面定义的 App 组件。
接入 Webpack目前最成熟和流行的开发 Vue 项目的方式是采用 ES6 加 Babel 转换,这和基本的采用 ES6 开发的项目很相似,差别在于要解析 .vue 格式的单文件组件。 好在 Vue 官方提供了对应的 vue-loader 可以非常方便的完成单文件组件的转换。
修改 Webpack 相关配置如下:
module: { rules: [ { test: /.vue$/, use: ["vue-loader"], }, ] }
安装新引入的依赖:
# Vue 框架运行需要的库 npm i -S vue # 构建所需的依赖 npm i -D vue-loader css-loader vue-template-compiler
在这些依赖中,它们的作用分别是:
vue-loader:解析和转换 .vue 文件,提取出其中的逻辑代码 script、样式代码 style、以及 HTML 模版 template,再分别把它们交给对应的 Loader 去处理。
css-loader:加载由 vue-loader 提取出的 CSS 代码。
vue-template-compiler:把 vue-loader 提取出的 HTML 模版编译成对应的可执行的 JavaScript 代码,这和 React 中的 JSX 语法被编译成 JavaScript 代码类似。预先编译好 HTML 模版相对于在浏览器中再去编译 HTML 模版的好处在于性能更好。
使用 TypeScript 编写 Vue 应用从 Vue 2.5.0+ 版本开始,提供了对 TypeScript 的良好支持,使用 TypeScript 编写 Vue 是一个很好的选择,因为 TypeScript 能检查出一些潜在的错误。
新增 tsconfig.json 配置文件,内容如下:
{ "compilerOptions": { // 构建出 ES5 版本的 JavaScript,与 Vue 的浏览器支持保持一致 "target": "es5", // 开启严格模式,这可以对 `this` 上的数据属性进行更严格的推断 "strict": true, // TypeScript 编译器输出的 JavaScript 采用 es2015 模块化,使 Tree Shaking 生效 "module": "es2015", "moduleResolution": "node" } }
修改 App.vue 脚本部分内容如下:
注意 script 标签中的 lang="ts" 是为了指明代码的语法是 TypeScript。
修改 main.ts 执行入口文件为如下:
import Vue from "vue" import App from "./App.vue" new Vue({ el: "#app", render: h => h(App) });
由于 TypeScript 不认识 .vue 结尾的文件,为了让其支持 import App from "./App.vue" 导入语句,还需要以下文件 vue-shims.d.ts 去定义 .vue 的类型:
// 告诉 TypeScript 编译器 .vue 文件其实是一个 Vue declare module "*.vue" { import Vue from "vue"; export default Vue; }
Webpack 配置需要修改两个地方,如下:
const path = require("path"); module.exports = { resolve: { // 增加对 TypeScript 的 .ts 和 .vue 文件的支持 extensions: [".ts", ".js", ".vue", ".json"], }, module: { rules: [ // 加载 .ts 文件 { test: /.ts$/, loader: "ts-loader", exclude: /node_modules/, options: { // 让 tsc 把 vue 文件当成一个 TypeScript 模块去处理,以解决 moudle not found 的问题,tsc 本身不会处理 .vue 结尾的文件 appendTsSuffixTo: [/.vue$/], } }, ] }, };
除此之外还需要安装新引入的依赖:npm i -D ts-loader typescript
为单页应用生成HTML 引入问题在使用 React 框架中,是用最简单的 Hello,Webpack 作为例子让大家理解, 这个例子里因为只输出了一个 bundle.js 文件,所以手写了一个 index.html 文件去引入这个 bundle.js,才能让应用在浏览器中运行起来。
在实际项目中远比这复杂,一个页面常常有很多资源要加载。接下来举一个实战中的例子,要求如下:
项目采用 ES6 语言加 React 框架。
给页面加入 Google Analytics,这部分代码需要内嵌进 HEAD 标签里去。
给页面加入 Disqus 用户评论,这部分代码需要异步加载以提升首屏加载速度。
压缩和分离 JavaScript 和 CSS 代码,提升加载速度。
在开始前先来看看该应用最终发布到线上的代码。
可以看到部分代码被内嵌进了 HTML 的 HEAD 标签中,部分文件的文件名称被打上根据文件内容算出的 Hash 值,并且加载这些文件的 URL 地址也被正常的注入到了 HTML 中。
解决方案推荐一个用于方便地解决以上问题的 Webpack 插件 web-webpack-plugin。 该插件已经被社区上许多人使用和验证,解决了大家的痛点获得了很多好评,下面具体介绍如何用它来解决上面的问题。
首先,修改 Webpack 配置。
以上配置中,大多数都是按照前面已经讲过的内容增加的配置,例如:
增加对 CSS 文件的支持,提取出 Chunk 中的 CSS 代码到多带带的文件中,压缩 CSS 文件;
定义 NODE_ENV 环境变量为 production,以去除源码中只有开发时才需要的部分;
给输出的文件名称加上 Hash 值;
压缩输出的 JavaScript 代码。
但最核心的部分在于 plugins 里的:
new WebPlugin({ template: "./template.html", // HTML 模版文件所在的文件路径 filename: "index.html" // 输出的 HTML 的文件名称 })
其中 template: "./template.html" 所指的模版文件 template.html 的内容是:
该文件描述了哪些资源需要被以何种方式加入到输出的 HTML 文件中。
以 为例,按照正常引入 CSS 文件一样的语法来引入 Webpack 生产的代码。href 属性中的 app?_inline 可以分为两部分,前面的 app 表示 CSS 代码来自名叫 app 的 Chunk 中,后面的 _inline 表示这些代码需要被内嵌到这个标签所在的位置。
同样的 表示 JavaScript 代码来自相对于当前模版文件 template.html 的本地文件 ./google_analytics.js, 而且文件中的 JavaScript 代码也需要被内嵌到这个标签所在的位置。
也就是说资源链接 URL 字符串里问号前面的部分表示资源内容来自哪里,后面的 querystring 表示这些资源注入的方式。
除了 _inline 表示内嵌外,还支持以下属性:
_dist 只有在生产环境下才引入该资源;
_dev 只有在开发环境下才引入该资源;
_ie 只有IE浏览器才需要引入的资源,通过 [if IE]>resource 注释实现。
这些属性之间可以搭配使用,互不冲突。例如 app?_inline&_dist 表示只在生产环境下才引入该资源,并且需要内嵌到 HTML 里去。
WebPlugin 插件还支持一些其它更高级的用法,详情可以访问该项目主页阅读文档。
管理多个单页应用 引入问题在开始前先来看看该应用最终发布到线上的代码。
构建出的目录结构为:
dist ├── common_029086ff.js ├── common_7cc98ad0.css ├── index.html ├── index_04c08fbf.css ├── index_b3d3761c.js ├── login.html ├── login_0a3feca9.js └── login_e31e214b.css
如果按照上节的思路,可能需要为每个单页应用配置一段如下代码:
new WebPlugin({ template: "./template.html", // HTML 模版文件所在的文件路径 filename: "login.html" // 输出的 HTML 的文件名称 })
并且把页面对应的入口加入到 enrty 配置项中,就像这样:
entry: { index: "./pages/index/index.js",// 页面 index.html 的入口文件 login: "./pages/login/index.js",// 页面 login.html 的入口文件 }
当有新页面加入时就需要修改 Webpack 配置文件,新插入一段以上代码,这会导致构建代码难以维护而且易错。
解决方案项目源码目录结构如下:
├── pages │ ├── index │ │ ├── index.css // 该页面多带带需要的 CSS 样式 │ │ └── index.js // 该页面的入口文件 │ └── login │ ├── index.css │ └── index.js ├── common.css // 所有页面都需要的公共 CSS 样式 ├── google_analytics.js ├── template.html └── webpack.config.js
从目录结构中可以看成出下几点要求:
所有单页应用的代码都需要放到一个目录下,例如都放在 pages 目录下;
一个单页应用一个多带带的文件夹,例如最后生成的 index.html 相关的代码都在 index 目录下,login.html 同理;
每个单页应用的目录下都有一个 index.js 文件作为入口执行文件。
虽然 AutoWebPlugin 强制性的规定了项目部分的目录结构,但从实战经验来看这是一种优雅的目录规范,合理的拆分了代码,又能让新人快速的看懂项目结构,也方便日后的维护。
Webpack 配置文件修改如下:
See the Pen webpack管理多个单页应用 by whjin (@whjin) on CodePen.