# webpack-revolution **Repository Path**: oscarzheng/webpack-revolution ## Basic Information - **Project Name**: webpack-revolution - **Description**: https://github.com/Aquariuslt/webpack-revolution webpack and gulp - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2017-08-31 - **Last Updated**: 2024-12-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Webpack Revolution 目录: - [Pure AngularJS Project](https://github.com/Aquariuslt/Webpack-Revolution/tree/master/pure-angularjs-project) - [Pure CommonJS Project](https://github.com/Aquariuslt/Webpack-Revolution/tree/master/pure-commonjs-project) - [Simple-Webpack-AngularJS](https://github.com/Aquariuslt/Webpack-Revolution/tree/master/simple-webpack-angularjs) - [Webpack-Gulp-AngularJS](https://github.com/Aquariuslt/Webpack-Revolution/tree/master/webpack-gulp-angularjs) - [Webpack-Gulp-AngularJS-Boilerplate](https://github.com/Aquariuslt/Webpack-Revolution/tree/master/webpack-gulp-angularjs-boilerplate) ## 前言 该代码示例描述了一个普通的前端项目进化到使用Webpack + Gulp 管理构建流的过程. 提供了一个现代化JavaScript工程化项目的模板与思路. 预备知识: - 一些基础的`AngularJS`知识 - 一些`angular-ui-router`的知识 - `Webpack`的作用与简介 - `Gulp`的作用与简介 [代码下载](https://github.com/Aquariuslt/Webpack-Revolution) ![Project-Structure](https://ooo.0o0.ooo/2017/05/21/59210e605f1c3.png) 示例项目里面包含了若干个子项目,以上图红圈内的几个项目文件夹为示例: 从上往下依次是: 1. 最原始的AngularJS项目 2. 使用Webpack构建的,以CommonJS方式编写的JS项目 3. 结合1,2的项目,使用Webpack,以CommonJS编写的AngularJS项目 5. 在3的基础上,使用Gulp任务流进行Webpack构建的一个AngularJS项目 4. 在5的基础上,将原来的AngularJS项目拆分成模块化,并添加CSS构建等模块 > P.S.为什么上面的顺序5和4会对调?因为在Github的网页上面显示的顺序不太对,按照字典序的排序 应该 `webpack-gulp-angularjs` 会在 `webpack-gulp-angularjs-boilerplate` 之前 接下来请跟着文档的步骤,下载项目自己动手运行. 运行需求环境: git >=3 npm >=3 node >=6 ## Getting Start ### 把项目下载到本地 ```bash git clone https://github.com/Aquariuslt/Webpack-Revolution.git cd Webpack-Revolution ``` ## Pure-AngularJS-Project ### 安装项目依赖 ``` cd pure-angularjs-project npm install ``` ### 项目说明 项目的文件夹目录大概如下 ``` Macbook:pure-angularjs-project Aquariuslt$ tree . ├── README.md ├── package.json ├── server.js ├── static │ ├── favicon.ico │ ├── index.html │ └── js │ ├── app │ │ ├── app.js │ │ └── routes.js │ └── vendor │ ├── angular-ui-router.js │ └── angular.js ``` 这是一个很原始的JavaScript项目,通过手动在`static/index.html`中添加JS,CSS文件的引用,接着使用`express`将`static`这个文件夹下的内容当成静态的前端资源文件提供出来. ### 运行项目 运行`npm start` 之后,我们可以在浏览器的[http://127.0.0.1:3000](http://127.0.0.1:3000) 看到效果 ![pure-angularjs-project-runtime-min.gif](https://ooo.0o0.ooo/2017/05/21/592143245b71e.gif) ### 代码说明 1.static/index.html ```html Pure AngularJS Application

Pure AngularJS Application

Home About ``` 负责引入`angular.js`,`angular-ui-router.js` 以及项目开发者自行编写的`app.js`与`routes.js` 2.static/app/app.js ```javascript (function () { angular.module('ita-app', ['ui.router'] ) })(); ``` 此处注册一个angular的module,叫做`ita-app` 3.static/app/routes.js ```javascript (function () { angular.module('ita-app') .config(function ($stateProvider) { $stateProvider .state({ name: 'default', url: '', template: '

Hello ITA

' }) .state({ name: 'home', url: '/', template: '

Hello ITA

' }) .state({ name: 'about', url: '/about', template: '

About: This is an ITA Application

' }); }); })(); ``` 此处声明`ui-router`的三个路由的url: 分别是`/`, `/about` 4.server.js ```javascript var express = require('express'); var app = express(); app.use('/', express.static('static')); app.listen(3000); ``` 此处表示使用express 监听3000端口,并以项目文件夹下的`static`作为静态资源的文件来提供服务. ### 总结 如同上面的运行时的GIF所示. 在不同的路由情况下,页面展现的内容不一样. 相信这个内容,在接触了Node.js的`express.js` 与`angular.js` 基本知识之后都能很容易的理解,简直是小菜一碟! ## Pure-CommonJS-Project 在了解了前面一个课程之后,我们开始接触最基础的一个利用Webpack打包的CommonJS的项目. 该样例的目的有两个: 其一是Webpack的简单Demo. 其二是使用Node.js的CommonJS语法进行JavaScript模块的导入导出. 说明流程是 先运行 后解释 先运行后解释! ### 安装项目依赖 ```bash cd pure-commonjs-project npm install ``` ### 项目说明 项目目录大以及说明概如下: ``` ├── README.md ├── package.json ├── server.js ├── src │ ├── app │ │ ├── bar.js --模块bar │ │ └── foo.js --模块foo │ ├── index.html --默认的index.html │ └── main.js --项目的前端入口JavaScript文件 ├── webpack.config.js --Webpack约定的默认配置文件名 ``` ### 运行项目 ```bash npm start ``` ![pure-commonjs-project-start.png](https://ooo.0o0.ooo/2017/05/21/59214b2da94f7.png) 命令行里面会出现webpack打包的输出 之后在浏览器查看[http://127.0.0.1:3001](http://127.0.0.1:3001) 应该如下图般显示: ![pure-commonjs-prject-browser.png](https://ooo.0o0.ooo/2017/05/21/59214c1125273.png) 好,自己动手的过程到此告一段落. 请继续阅读文档下面的部分,看看中间到底发生了什么. ### 过程简介 在运行`npm start`之后,到底经过了什么样的操作呢? 大概是如下一个流程: 1.`npm start`命令,先指向了`package.json`里面`scripts`部分的`start`. 以`package.json`文件为例:`npm start`指向了一个`webpack && node server.js`的命令. ```json { "name": "pure-commonjs-project", "version": "1.0.0", "main": "index.js", "license": "MIT", "scripts": { "start": "webpack && node server.js" }, "dependencies": { "express": "^4.15.3" }, "devDependencies": { "html-webpack-plugin": "^2.28.0", "webpack": "^2.5.1" } } ``` 该命令表示,当全局安装了webpack,或者项目的`node_modules/.bin/`下面有webpack的可执行文件的时候.可以通过内置的命令`webpack`来执行打包的功能. 当执行完命令`webpack`之后,开始执行`node server.js`这一句命令. 使用`express.js`监听某个端口(3001),对某个文件夹(public)进行静态资源的监控. 讲到这里,相信大家已经大概知道 1.`npm start` 实际调用的其他命令 2.`webpack`这个命令,会执行打包构建的工作,把构建好的文件输出到指定的文件夹. `webpack`命令的详细工作流程,在接下来的部分会讲到. ### 代码说明 在逐个代码文件进行说明的时候,可能发现整个项目的文件夹名字都跟第一个项目`pure-angularjs-project`有所不同了. 遵循主流的JavaScript前端项目的约定,我们把 项目的`index.html`和其他源代码的部分都放在`src`文件夹下. 将最后编译/构建/打包的文件都放在`public`文件夹下. > 对于`public`文件夹这个命名,流行的别名有很多,这里取`public`为例子 > 还有一些其他流行的别名都可以使用: > 譬如`static`(意为静态资源文件,第一个项目就是用这个来命名). > 又如`dist`(意为distribution) > 这些命名地位和意义相等,没有争论的必要,都可以用 对于代码说明, 我们先看`webpack.config.js`这个webpack的配置文件. 再对`src`下的源代码文件做逐一说明. 1.webpack.config.js 刚刚在执行`npm start`命令的时候,有些同学可能有困惑: "我只执行了`webpack`这个命令,他怎么就帮我全部打包到`public`文件夹了?" 其实`webpack`命令执行的时候,按照其官方文档提供的说明和*约定*,在不指定任何参数的时候,默认会去读取项目目录下的`webpack.config.js` 所以使用纯的命令`webpack`,就相当于执行`webpack --conf webpack.config.js`. 去读取该配置文件进行打包. 现在我们来看一下`webpack.config.js`的内容 ```javascript var path = require('path'); var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { main: './src/main.js' }, output: { path: path.resolve('public'), publicPath: '', filename: '[name].bundle.js', chunkFilename: '[id].[hash].chunk.js' }, resolve: { extensions: ['.js'] }, plugins: [ new HtmlWebpackPlugin({ template: 'src/index.html' }) ] }; ``` 需要注意的几个部分是: ```javascript entry: { main: './src/main.js' } ``` `entry`部分说明了webpack将以`src/main.js`为打包的入口文件. 将其require的层层依赖最后都打包到一个文件里面. ```javascript output: { path: path.resolve('public'), publicPath: '', filename: '[name].bundle.js', chunkFilename: '[id].[hash].chunk.js' } ``` `output`部分说明了webpack读取入口文件之后,打包好的项目代码,以怎样的形式 输出. 在上面的例子中 `path`表示把所有的输出文件都放到`public`文件夹中. `filename`表示输出的`javascript`文件需要如何命名,这里的意思是,如果入口文件名为`main.js`,根据webpack对`[name].bundle.js`的格式化处理,将会输出成`main.bundle.js` 剩余的`publicPath`,`chunkFilename`目前暂时不用关心. ```javascript plugins: [ new HtmlWebpackPlugin({ template: 'src/index.html' }) ] ``` webpack有很多插件(包括官方提供的,和流行的第三方插件). 在配置文件的`plugins`字段描述了按生命的顺序加载并使用该插件对输出的文件进行处理. 里面用到的`HtmlWebpackPlugin`是一个很常用的插件, 在这里的意思大概是,他会以`src/index.html`作为模板,最后把输出的javascript,css等资源文件的链接插入到`index.html`合适的地方. 2.main.js ``` require('./app/foo'); require('./app/bar'); console.log('load main.js'); document.write('

Load main.js

'); module.exports = {}; ``` main.js作为入口文件,他希望做到的是先加载`foo.js`与`bar.js` 接着执行自己的内容,在控制台输出`load main.js` 接着在body里面插入一条`h1`的标签. 3.app/foo.js 与 app/bar.js foo.js ```javascript console.log('load foo.js'); document.write('

Load foo.js

'); module.exports = {}; ``` bar.js ```javascript console.log('load bar.js'); document.write('

Load bar.js

'); module.exports = {}; ``` foo.js 与 bar.js 如字面意思. 4.index.html ```html CommonJS Project ``` 需要注意的是,这里的`index.html`文件是没有任何引用javascript,css文件的显式声明的. 这就是上面提及的`webpack.config.js`里面的`HtmlWebpackPlugin`所做的工作! 可以对比一下作为原始模板的`src/index.html`与构建之后的`public/index.html`: ```html CommonJS Project ``` webpack 在构建过程中插入了`main.bundle.js`的引用! ### 思考 以CommonJS的语法进行前端JavaScript代码的编写. 模块加载顺序,与直接内嵌在html文件中有什么不同? 如下图,我们把对`src/app/foo.js`的引用注释掉,再执行`npm start`. 构建后的代码有什么不同?浏览器的内容跟浏览器控制台输出的内容有什么不同? ```javascript //require('./app/foo'); require('./app/bar'); console.log('load main.js'); document.write('

Load main.js

'); module.exports = {}; ``` ### 总结 通过这个普通的Webpack的Demo. 你应该体会到: 1. Webpack 构建打包的基础过程 2. 开始学习并习惯以CommonJS形式编写前端的JavaScript代码(这里的CommonJS形式并非JavaScript项目的模块化概念!) 并可能触发一些思考: - 如何与`angular.js`,`jquery`甚至其他主流的javascript框架结合使用? - 如何对webpack的配置进行根据不同环境的可配置化?(本地开发,生产环境,测试环境) ...... ## Simple-Webpack-AngularJS 在了解完前面两个项目的代码之后. 你见识到了: - 一个最基础的可运行的`angularjs`项目 - 一个最基础的用`webpack`构建的js项目 那么如何结合两者,变成一个 用`webpack`构建的`angularjs`项目呢? `simple-webpack-angularjs` 该项目的内容,即使一个结合第一和第二个项目代码样例而成的,用`webpack`构建的`angularjs`项目样例. 在展现出来的效果看,跟`pure-angularjs-project`的效果是一样的. > 该项目样例在尽量不修改大量配置的情况下,实现了所需要的功能 > 实际上,该项目的配置,结构 还离 功能齐全的 可配置化的实际项目的结构 > 有稍大的差距.还不能作为一个正式的手脚架使用. > 不过作为学习项目演变过程的样例,希望同学们能够从中汲取到一些关于webpack的知识. ### 安装项目依赖 ```bash cd simple-webpack-angularjs npm install ``` ### 项目说明 项目的结构大概如下 ``` ├── README.md ├── package.json ├── server.js ├── src │ ├── app │ │ └── routes.js │ ├── favicon.ico │ ├── index.html │ └── main.js ├── webpack.config.js ``` 结构与`pure-common-js`大概相同. 其中需要说明的是: `src/app/routes.js` 等同于 第一个项目的 `static/js/app/routes.js` `src/main.js`作为入口的js文件,功能上等同于第一个项目的`static/js/app/app.js` ### 运行项目 ```bash npm start ``` 命令行里面会出现webpack打包的输出 之后在浏览器查看[http://127.0.0.1:4000](http://127.0.0.1:4000) > 为了使多个项目能够同时运行方便比较,所以端口号分别取了3000,3001,4000端口 ![simple-webpack-angularjs-min.gif](https://ooo.0o0.ooo/2017/05/21/592175cea4292.gif) ### 代码说明 主要查看的是 `src/main.js`,`src/app/routes.js` 1.main.js ```javascript var angular = require('angular'); var uirouter = require('@uirouter/angularjs'); // import your routes config var appRoutes = require('./app/routes'); module.exports = angular.module('ita-app', [ 'ui.router' ]) .config(appRoutes) ; ``` 此时回顾一下`pure-angularjs-project`的`app.js` ```javascript (function () { angular.module('ita-app', ['ui.router'] ) })(); ``` 我们可以看出`app.js` 里面只声明了`ita-app`的模块和对`ui.router`的依赖,没有声明route. 而在`main.js`里面: 先用`require('angular')`,`require('@uirouter/angularjs')` 对第三方的`angularjs`,`angular-ui-router`进行引用. 接着再声明一个新的叫`ita-app`的模块. 并且将该模块下声明的route都加载到这里 2.app/routes.js ```javascript module.exports = function ($stateProvider) { $stateProvider .state({ name: 'default', url: '', template: '

Hello ITA

' }) .state({ name: 'home', url: '/', template: '

Hello ITA

' }) .state({ name: 'about', url: '/about', template: '

About: This is an ITA Application

' }); }; ``` 此时在回顾一下`pure-angularjs-project`的`route.js` ```javascript (function () { angular.module('ita-app') .config(function ($stateProvider) { $stateProvider .state({ name: 'default', url: '', template: '

Hello ITA

' }) .state({ name: 'home', url: '/', template: '

Hello ITA

' }) .state({ name: 'about', url: '/about', template: '

About: This is an ITA Application

' }); }); })(); ``` 与`pure-angularjs-project` 的 `routes.js`相比 主体功能是完全一样的,只需要export出去,在模块声明的地方用 `angular.module(moduleName,[]).config(${export的部分})`即可 实际运行效果是一样的. > P.S. 找个在读的小伙伴测了下 貌似对上面这句不理解. > 可以参考下面两个图,是相等的: ![1.png](https://ooo.0o0.ooo/2017/05/21/592187834c401.png) ![2.png](https://ooo.0o0.ooo/2017/05/21/5921878345d59.png) ### 思考 1. 查看生成的`public/main.bundle.js` 是否发现`angular.js`的源代码和`@uirouter/angularjs`的源代码已经包含在里面? 是否应该将业务代码与第三方依赖代码分开储存? 项目协作人数越来越多的时候,如何利用CommonJS的模块语法,实现AngularJS工程的模块化? 打包到一起的时候,如何在浏览器中方便的调试业务代码? 部署上生产环境的时候,是否需要制定不同环境的配置,譬如生产环境JS压缩等操作? ### 总结 该项目提供了一个使用angularjs,利用CommonJS语法组织工程代码,使用Webpack进行构建打包的一个样例. ## Webpack-Gulp-AngularJS 通过基本的前端项目工程化的介绍, 我们大概了解了: - Webpack的简介 - Gulp的简介与定位 通过之前的几个样例代码, 我们大概了解了: - Webpack的基本使用方法 - Webpack的基本配置 - 使用CommonJS 编写原来的AngularJS项目 请注意回顾到里面样例代码的演变形式, 因为这一章节,主要的改动是引入gulp来使得项目构建流程化. 如果在阅读文档并且动手操作之后,还不了解前面1,2,3 三个部分的演变过程请将疑问提到[issues](https://github.com/Aquariuslt/Webpack-Revolution/issues)里面. 会根据情况进行文档的补充. 如果没有足够的理解,那么可能在阅读这一章节的时候就可能变成以下这个情况: ![算术入门.jpg](https://ooo.0o0.ooo/2017/05/23/5923c9999692c.jpg) 如果顺利的话,在这一章节,我们将了解以下的部分内容: - 划分不同环境的Webpack构建配置 - Gulp与常见Gulp插件的一些介绍与使用 - Webpack与Gulp的结合使用 - Webpack-Dev-Server 带来的开发体验的巨大提升 涉及的项目文件更变有点多. 中间有任何不明白的地方 请立刻提issue, 以便做出修改 达到更好的教学效果.谢谢~ ### 安装项目依赖 ```bash cd webpack-gulp-angularjs npm install ``` ### 项目说明 之前的项目里面,都是先运行,再解释. 这个章节的流程不一样: 1. 先讲述一些应用场景,了解背景 2. 再讲述改项目样例参考的灵感来源 3. 再介绍项目改变的部分 4. 介绍新增的部分的工具以及example的说明 ##### 生产环境与开发环境的配置分离 无论是大小项目,可能都需要区分本地开发环境(Development),生产环境(Production/Release). 规模稍大以致能够更细分成本地开发环境,测试环境,集成开发环境,预生产环境 等更多不同的环境. 在不同的环境里面,项目展现出的各种配置可能不一样. 以JavaScript前端项目为例子. 可能不同环境的配置是不一样的,展现出来的区分在于: 本地开发环境: - 浏览器展现出的JavaScript代码,方便调试,定位问题.CSS,JS不会经过压缩,混淆,合并. - 控制台输出全部级别的日志. - API请求连接到的是本地/测试环境的后台服务器 - .... 生产环境: - 为了符合最佳网站实践,浏览器加载页面时候的静态资源文件大小尽量小,请求数尽量少 - 控制台也不输出调试日志. - .... 因此,根据此项目的情况,我们会将使用webpack构建的过程,分成本地开发环境,与生产环境两种配置. 在下文的文件说明中,会详细提及他们之间的变化. 现在大概对不同环境下,对应不同构建配置的必要性有个基本的了解了吧. ##### 构建任务流 如果之前接触过maven,或者gradle,可以发现: 在J2EE项目中,通常本地构建会有一些构建任务 使用maven的话 使用命令: ```bash mvn clean mvn package ``` 抑或是使用gradle: ```bash gradle clean gradle build ``` 这些都可以理解成包管理器/构建工具内置的任务流之一. `xxx clean`的意思就是清除(删除)所有构建生成的文件. `xxx package`的意思是编译并打包构建好的文件. 转换到node.js的情景: 既然npm本身不会带有这方面的内置的任务流(对于项目构建生成的文件,也没有约定在某一个/几个目录,比如maven的`/target`,gralde的`/build`). 所以一般是使用主流的任务流工具:gulp或者grunt 来代替完成这部分的工作. 参考过大部分主流的前端项目: - Angular4团队 `@angular/cli`内置的webpack任务流 - `vue-cli`中使用webpack构建的任务流 - 其他主流项目 从这些项目中了解到的一些任务流的命名. > P.S. 仅仅是希望大家能接受这种命名,不是我突发奇想,胡乱想出来的一些命名 如果使用gulp作为任务流工具,我们根据不同环境拆分配置的时候. 可能会有以下的任务流: - gulp clean 清除默认的构建中生成的文件夹 - gulp build 构建用于部署的,生产环境用到的文件 - gulp serve 本地开发时,用于提供web服务的命令 - gulp test 执行单元测试, 好,大概了解了这章节的样例代码所涉及的概念. 接下来就开始描述项目结构的更变吧. ##### 项目结构 在实现与样例`pure-angularjs-project`,`simple-webpack-angularjs`相同的效果的情况下: 项目的结构大概如下: ``` . ├── README.md ├── gulpfile.js ├── package.json ├── src │ ├── app │ │ └── routes.js │ ├── favicon.ico │ ├── index.html │ └── main.js ├── tasks │ ├── build.js │ ├── clean.js │ ├── config │ │ ├── base.config.js │ │ ├── webpack.base.config.js │ │ ├── webpack.dev.config.js │ │ └── webpack.prod.config.js │ ├── serve.js │ └── util │ └── path-util.js └── yarn.lock ``` 项目结构更变概括: 1. 在webpack的配置方面,为了拆分本地开发环境,我们将原来的位于项目根文件夹的`webpack.config.js`拆分成以下形式: ![webpack-config-dependencies.png](https://ooo.0o0.ooo/2017/05/23/5923f187ea0c8.png) > P.S. 注意加粗黄线的部分,才是要注意的地方 现在把`webpack.config.js` 拆分成`webpack.base.config.js`,`webpack.dev.config.js`,`webpack.prod.config.js`三个文件 其中`webpack.dev.config`是基于`webpack.base.config`的开发运行时配置 而`webpack.prod.config.js`是基于`webpack.base.config`的生产环境构建配置 因为中间配置的内容比较复杂,但项目技术框架选型定下之后(目前样例选择的是AngularJS),三个以webpack开头的配置文件改动频率相当小. 因此我把改动频率较大,只需开发者关心且修改频率可能很大的部分抽取到`base.config.js`里面. 等下会说明该部分内容. 2. 使用gulp进行构建任务流之后, 我们将通过 gulp 调用webpack进行前端代码的构建任务. 因此, webpack的配置文件,被移动到`tasks/config`文件夹中 我们将通过 `npm run dev`,`npm run build`,`npm run clean` 三个命令分别调用 `gulp serve`,`gulp build`,`gulp clean`. 根据 gulp 的约定, 执行gulp命令的时候,默认会读取 项目根目录下的 `gulpfile.js`加载task列表. 所以我们能看到`gulpfile.js`里面的内容,是导入`/tasks/`文件夹下的三个 tasks :`build`,`clean`,`serve` ```javascript require('./tasks/clean'); require('./tasks/build'); require('./tasks/serve'); ``` 项目文件更变说明到此结束. 下面开始运行项目,先运行,后面在代码说明小章节解释每份配置的内容. ### 运行项目 现在项目有三种tasks可以执行: - npm run clean: 表示清除项目构建生成的文件夹 - npm run build: 该task会先执行上面的`clean`操作,再以webpack生产环境配置,构建出生产环境需要用的静态资源文件 - npm run dev: 该task会启动一个`webpack-dev-server`,目前默认监听`5001`端口. 以webpack开发环境配置构建,可以将源代码内容的更变实时反映到浏览器上. 下面我们先按`build`,`clean`,`dev`这种顺序执行一次 1. build ```bash npm run build ``` 可以看到 执行 `gulp`的task的时候的一些输出 ``` [09:14:53] Starting 'build'... [09:14:53] Starting 'clean'... [09:14:53] Starting 'clean:build'... [09:14:53] Deleting build folder [09:14:53] Starting 'clean:dist'... [09:14:53] Deleting dist folder [09:14:53] Finished 'clean:build' after 14 ms [09:14:53] Finished 'clean:dist' after 7.12 ms [09:14:53] Finished 'clean' after 17 ms [09:14:53] Starting 'webpack'... [09:14:53] Webpack building. [09:14:59] Hash: 15ec065050c6b4d08cd6 Version: webpack 2.5.1 Time: 6444ms Asset Size Chunks Chunk Names main.2949cd4c297786231109.js 425 bytes 0 [emitted] main vendor.f7682f3c276a26fc48f2.js 301 kB 1 [emitted] [big] vendor main.2949cd4c297786231109.js.map 2.69 kB 0 [emitted] main vendor.f7682f3c276a26fc48f2.js.map 3.96 MB 1 [emitted] vendor favicon.ico 5.43 kB [emitted] index.html 534 bytes [emitted] chunk {0} main.2949cd4c297786231109.js, main.2949cd4c297786231109.js.map (main) 711 bytes {1} [initial] [rendered] [59] ./src/app/routes.js 438 bytes {0} [built] [89] ./src/main.js 273 bytes {0} [built] chunk {1} vendor.f7682f3c276a26fc48f2.js, vendor.f7682f3c276a26fc48f2.js.map (vendor) 1.7 MB [entry] [re ndered] [4] ./~/@uirouter/core/lib/index.js 674 bytes {1} [built] [22] ./~/angular/index.js 48 bytes {1} [built] [23] ./~/@uirouter/angularjs/lib/services.js 6.36 kB {1} [built] [24] ./~/@uirouter/angularjs/lib/statebuilders/views.js 5.57 kB {1} [built] [31] ./~/@uirouter/angularjs/lib/stateProvider.js 6.14 kB {1} [built] [32] ./~/@uirouter/angularjs/lib/urlRouterProvider.js 7.66 kB {1} [built] [33] ./~/@uirouter/core/lib/globals.js 1.18 kB {1} [built] [58] ./~/@uirouter/angularjs/lib/index.js 721 bytes {1} [built] [60] ./~/@uirouter/angularjs/lib/directives/stateDirectives.js 24.4 kB {1} [built] [61] ./~/@uirouter/angularjs/lib/directives/viewDirective.js 15.9 kB {1} [built] [62] ./~/@uirouter/angularjs/lib/injectables.js 12.9 kB {1} [built] [64] ./~/@uirouter/angularjs/lib/stateFilters.js 1.51 kB {1} [built] [67] ./~/@uirouter/angularjs/lib/viewScroll.js 793 bytes {1} [built] [83] ./~/@uirouter/core/lib/url/index.js 385 bytes {1} [built] [88] ./~/angular/angular.js 1.25 MB {1} [built] + 73 hidden modules Child html-webpack-plugin for "index.html": Asset Size Chunks Chunk Names index.html 545 kB 0 chunk {0} index.html 541 kB [entry] [rendered] [0] ./~/lodash/lodash.js 540 kB {0} [built] [1] ./~/html-webpack-plugin/lib/loader.js!./src/index.html 817 bytes {0} [built] [2] (webpack)/buildin/global.js 509 bytes {0} [built] [3] (webpack)/buildin/module.js 517 bytes {0} [built] [09:14:59] Webpack build done [09:14:59] Finished 'webpack' after 6.52 s [09:14:59] Finished 'build' after 6.54 s ``` 之后查看生成的`public`文件夹 会发现有以下的文件: ``` favicon.ico index.html main.2949cd4c297786231109.js main.2949cd4c297786231109.js.map vendor.f7682f3c276a26fc48f2.js vendor.f7682f3c276a26fc48f2.js.map ``` `main.2949cd4c297786231109.js`是压缩后的以`src/main.js`为入口的,不包括`node_modules`里面代码引用的构建出来的代码. `vendor.f7682f3c276a26fc48f2.js`是压缩以后的,源代码中引用到的位于`node_modules`里面的代码. 这里包括了 `node_modules/angular/angular.js`,`node_modules/@uirouter/angularjs` `main.2949cd4c297786231109.js.map`,`vendor.f7682f3c276a26fc48f2.js.map` 是前面的两个js文件的`source map`文件. 作为生产环境反向追踪源代码的手段.(目前只有Chrome支持) > P.S. 因为webpack生产环境的配置里面output格式是`[name].[chunkhash].js`. > 所以中间的一串字符串是一个hash值,每次相同的源代码只会生成相同的chunkhash值 2. clean ``` npm run clean ``` 之后你会发现 `public` 文件夹已被删除 3. dev ``` npm run dev ``` 当看到terminal输出`webpack: Compiled successfully` 的时候,就可以打开浏览器 [http://127.0.0.1:5001](http://127.0.0.1:5001) 同时请打开浏览器的console观察变化. 此时: 我们把项目源代码的编辑器,与浏览器分别置于整个电脑桌面的左右两边. 在编辑器内打开`src/index.html`并尝试做出一些修改,譬如把`Simple Webpack Application`修改成`Not Simple Webpack Application`. 同时观察浏览器的变化,就能看到浏览器立刻自动刷新并且反映出了结果. 我们也可以修改`src/app/routes.js`里面的`home` state的template. 浏览器也能够自动刷新出效果! 这就是`webpack-dev-server`的作用之一. ### 代码说明 `tasks/util/path-util.js` 内容: ```javascript var path = require('path'); const _root = path.resolve(__dirname, '../..'); function root(args) { args = Array.prototype.slice.call(arguments, 0); return path.join.apply(path, [_root].concat(args)); } module.exports.root = root; ``` 说明: 有个必要说明的是这个`path-util.js` webpack的配置里面, 有一个容易跌坑的地方,便是路径的表示形式. 有一些路径的表示形式是根目录的相对路径,如`./src/main.js`. 有一些路径的表示形式则是配置文件当前路径的相对路径,譬如各种loaders的覆盖路径. 所以这个path-util 是为了方便地统一以根目录为原始路径,调用node.js原生的`path.resolve` api, 来获得统一的系统绝对路径. > P.S. 参考Angular官方文档中对webpack的一个tutorial[WEBPACK: AN INTRODUCTION](https://angular.io/docs/ts/latest/guide/webpack.html) > 中提及的一个工具类helpers `tasks/config/webpack.base.config.js` `tasks/config/webpack.base.config.js` 内容: ```javascript module.exports = { entry: { main: './src/main.js' }, resolve: { extensions: ['.js'] }, plugins: [] }; ``` 这里放的是公共的项目entry `tasks/config/webpack.dev.config.js` 内容 ```javascript var os = require('os'); var webpack = require('webpack'); var merge = require('webpack-merge'); var HtmlWebpackPlugin = require('html-webpack-plugin'); var baseConfig = require('./base.config'); var webpackBaseConfig = require('./webpack.base.config'); var pathUtil = require('../util/path-util'); const PROTOCOL = 'http://'; const HOST = '127.0.0.1'; const PORT = 5001; var webpackDevConfig = merge(webpackBaseConfig, { devtool: 'source-map', output: { path: pathUtil.root(baseConfig.dir.build), publicPath: PROTOCOL + HOST + ':' + PORT, filename: '[name].bundle.js', sourceMapFilename: '[name].bundle.js.map', chunkFilename: '[id].chunk.js' }, devServer: { host: HOST, port: PORT }, plugins: [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"development"' } }), new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks: function (module) { return ( module.resource && /\.js$/.test(module.resource) && module.resource.indexOf( pathUtil.root('node_modules') ) === 0 ); } }), new HtmlWebpackPlugin({ template: 'src/index.html', favicon: 'src/favicon.ico' }), new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin() ] }); module.exports = webpackDevConfig; ``` 说明: 这里开始配置文件相对上一个章节的样例,更变的非常多. 由于是本地开发时环境配置,所以多出的`devServer`选项指的是`webpack-dev-server`运行时的端口配置,本配置文件默认是5001端口. 在`plugins`方面: `webpack.DefinePlugin`声明了一个前端构建时的环境变量, 按照此代码中的说明 可以在前端文件中使用表达式`process.env.NODE_ENV`,在构建过程中会被转译为对应的`development`字符串,并且在浏览器中不能通过 手敲'process.env.NODE_ENV' 取值. > 参考Webpack Definition Plugin[官方文档](https://webpack.js.org/plugins/define-plugin/) 名为`vendor`的`webpack.optimize.CommonsChunkPlugin`的作用,则是将`angularjs`,`@uirouter/angularjs`这种第三方的类库与业务应用的代码分割成不同的文件. > 思考: 这样分割的好处是什么? `tasks/config/webpack.prod.config.js` 内容: ```javascript var webpack = require('webpack'); var merge = require('webpack-merge'); var HtmlWebpackPlugin = require('html-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); var CopyWebpackPlugin = require('copy-webpack-plugin'); var baseConfig = require('./base.config'); var webpackBaseConfig = require('./webpack.base.config'); var pathUtil = require('../util/path-util'); var webpackProdConfig = merge(webpackBaseConfig, { devtool: 'source-map', output: { path: pathUtil.root(baseConfig.dir.dist), filename: '[name].[chunkhash].js', chunkFilename: '[id].[chunkhash].js' }, plugins: [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"production"' } }), new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks: function (module) { return ( module.resource && /\.js$/.test(module.resource) && module.resource.indexOf( pathUtil.root('node_modules') ) === 0 ); } }), new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false }, sourceMap: true }), new webpack.LoaderOptionsPlugin({ minimize: true }), new OptimizeCssAssetsPlugin({ cssProcessorOptions: { safe: true, discardComments: { removeAll: true } }, canPrint: false }), new ExtractTextPlugin({ filename: '[name].[chunkhash].css' }), new HtmlWebpackPlugin({ template: './' + baseConfig.dir.src + '/index.html', favicon: './' + baseConfig.dir.src + '/favicon.ico', inject: true, minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: false }, chunksSortMode: 'dependency' }) ] }); module.exports = webpackProdConfig; ``` 说明: 对于生产环境的配置,则主要是对构建出的文件做一连串的上线前准备, 包括但不限于: - 最小化静态资源文件体积 - 将文件hash值加入到文件命名中 - ..... > 思考: 这里能看到一些与dev.config相同的plugins 配置,为什么会这样? `tasks/clean.js` 内容: ```javascript var gulp = require('gulp'); var rimraf = require('gulp-rimraf'); var sequence = require('gulp-sequence'); var gutil = require('gulp-util'); var baseConfig = require('./config/base.config'); gulp.task('clean', sequence(['clean:build', 'clean:dist'])); gulp.task('clean:build', function () { gutil.log('Deleting build folder'); return gulp.src(baseConfig.dir.build) .pipe(rimraf()); }); gulp.task('clean:dist', function () { gutil.log('Deleting dist folder'); return gulp.src(baseConfig.dir.dist) .pipe(rimraf()); }); ``` 说明: `clean:dist`,`clean:build`,`clean` 作用都是删除对应的文件夹. 介绍一下这里用到的`gulp`插件: - `gulp-rimraf` 用于删除对应文件夹 - `gulp-sequence` gulp 任务流的顺序控制 - `gulp-util`常用来输出调试信息 `tasks/build.js` 内容: ```javascript var gulp = require('gulp'); var gutil = require('gulp-util'); var sequence = require('gulp-sequence'); var webpack = require('webpack'); var webpackProdConfig = require('./config/webpack.prod.config'); gulp.task('webpack', function (done) { gutil.log('Webpack building.'); webpack(webpackProdConfig, function (error, stats) { if (error) { throw new gutil.PluginError('webpack', error); } gutil.log(stats.toString(webpackProdConfig.stats)); gutil.log('Webpack build done'); done(); }); }); gulp.task('build', sequence(['clean'], ['webpack'])); ``` 说明: build的任务流代码比较容易懂,意思就是先执行预先定义好的`clean`task. 接着执行`webpack`task: 根据`webpack.prod.config.js`构建出生产环境的资源文件 `tasks/serve.js` 内容: ```javascript var gulp = require('gulp'); var gutil = require('gulp-util'); var sequence = require('gulp-sequence'); var webpack = require('webpack'); var WebpackDevServer = require('webpack-dev-server'); var addDevServerEntrypoints = require('webpack-dev-server/lib/util/addDevServerEntrypoints'); var webpackDevConfig = require('./config/webpack.dev.config'); gulp.task('serve', function () { gutil.log('Webpack building.'); gutil.log(webpackDevConfig.devServer.host + ':' + webpackDevConfig.devServer.port); addDevServerEntrypoints(webpackDevConfig, webpackDevConfig.devServer); var compilerConfig = webpack(webpackDevConfig); new WebpackDevServer(compilerConfig, webpackDevConfig.devServer) .listen(webpackDevConfig.devServer.port, webpackDevConfig.devServer.host, function (error) { if (error) { throw new gutil.PluginError('webpack', error); } }); }); ``` 说明: `serve`这个task,表示通过读取开发时webpack配置`webapck.dev.config`, 启动一个`webapck-dev-server`的实例. ### 总结 在这一章节,我们大概了解到了: - 使用gulp任务流控制webpack构建 - 拆分不同环境的webpack构建配置 ### 思考 - 那么CSS也能通过webpack构建吗, CSS的哪种模块导入导出语法能够被`webpack`或其`loaders`正确识别? - 那么项目的静态媒体资源,比如图标,字体,固定的logo图片等应该如何配置,也需要使用 require进行管理吗?使用webpack管理媒体资源的主流工作方式是怎样的? - AngularJS 里面的directive,component,service,values,constant,service,factory等其他功能,应该如何以CommonJS的形式编写? - ...... ### 参考文章 [WebpackMerge是如何Merge Configuration的?](https://github.com/survivejs/webpack-merge) ## Webpack-Gulp-AngularJS-Boilerplate 通过上一节样例的解析,我们了解到了一个基本的`webpack`+`angularjs`+`gulp`结合的,稍有眉目的工程代码. 但是要应用到实际项目中,还有很多明显的问题需要解决,包括但不限于: 通用部分: - CSS,Fonts等资源文件如何进行打包? - Server代码不是Node.js应用,如何与其他类型的后端项目结合在一起吗? AngularJS部分: - 如何管理angularjs的视图部分的html文件? - 如何拆分angularjs的模块 这一章的样例代码,在上一章的基础上,添加了以下功能: - 利用webpack的`ng-cache-loader`解析angularjs `html`视图文件 - 利用webpack的`style-loader`,`css-loader`提供css文件构建样例 - 提供`angularjs`项目功能模块化的一种实现思路与实现 - 提供与`koa`,`express`,`springboot`等常见后台工程的整合方案 - 添加`bootstrap`的css样式 (有需要可自行替换) - 添加`angular-ui-bootstrap`作为基本的angular组件框架 (有需要可自行替换) - 添加了一个可选的`webpack-dev-server-proxy`方便开发环境与单独分离的后台进行整合 (详情请见下文代码说明) 为解决实际项目中遇到的问题做了其中一种实现,提供了一种较普遍的思路. ### 安装项目依赖 ```bash cd webpack-gulp-angularjs-boilerplate npm install ``` ### 运行项目 ```bash npm run dev ``` ### 与其他后台项目整合 与其他后台项目整合,前提是对后台项目的代码结构和运行过程有一定的了解, 本项目只从以下几个 ~~我只懂的~~ 技术栈展开描述: - Node.js - Express - Node.js - KOA2 - Java - SpringBoot(Maven) 我们先回顾一下`task/config/base.config.js`: 还记得`base.config.js`文件存在的意义吗? > P.S. 在上一章有提及到这一句: > 因此我把改动频率较大,只需开发者关心且修改频率可能很大的部分抽取到`base.config.js`里面. ```js module.exports = { dir: { src: 'src', build: 'build', // default: public // backend-springboot : ../backend-springboot/src/main/resources/public // backend-koa: ../backend-koa/public // backend-express: ../backend-express/public dist: 'public' } }; ``` 当前我们有三个后台类型的项目,没有任何功能,只是单纯的运行起来. 分别处于项目根目录下的`backend-express`,`backend-koa`,`backend-springboot`里面. 只要把`base.config.js`中的`dist`一值修改成 注释中的`backend-express`,`backend-koa`,`backend-springboot`其中一个的值. 在通过运行`npm run build`就能把生成的资源文件自动打包到对应项目的默认静态资源文件夹. 对于那些前后端项目相结合的项目,基本上生产环境的构建都可以通过这类指定输出目录/文件夹复制 的功能去实现. ### 代码说明 这一轮主为了实现上面提及的新功能, 添加的代码大概如下: - 添加`bootstrap`的css样式 (有需要可自行替换) - 利用webpack的`ng-cache-loader`解析angularjs `html`视图文件 - 利用webpack的`style-loader`,`css-loader`提供css文件构建样例 - 提供`angularjs`项目功能模块化的一种实现思路与实现 - 提供与`koa`,`express`,`springboot`等常见后台工程的整合方案 - 添加`angular-ui-bootstrap`作为基本的angular组件框架 (有需要可自行替换) - 添加了一个可选的`webpack-dev-server-proxy`方便开发环境与单独分离的后台进行整合 (详情请见下文代码说明) #### 依赖文件更变 因为使用了`bootstrap.css`和`angular-ui-router`,所以可以看到`package.json`里面多了这两个依赖. ##### bootstrap.css 在引入`bootstrap.css`方面, 修改的文件涉及下面几个方面: - 全局的 `styles.css` 文件入口 - `webpack.base.config`关于bootstrap.css中定义的 `Glyphicons` 相关icon-font 的loaders ###### 全局的styles.css入口 1. 在src文件夹下, 新增了一个 `styles.css` 这个文件,主要是用来做样式文件的一个entry. Q: 什么时候需要修改这个`styles.css`? A: 修改style.css 入口文件一般的情景有: - 新增了一些第三方(vendor)类库的, 样式文件位于 `node_modules` 文件夹下的css文件. - 自定义的一些其他可拆分的css/less/sass 文件 如此样例所示: 只需要在里面使用`@import` 语法进行引入即可 ``` @import "~bootstrap/dist/css/bootstrap.css"; ``` ###### webpack.config 新增 entry 同时也能看到`webpack.base.config,js`为了适应修改,新增了一个entry ``` entry: { main: './src/main.js' } ``` 变为 ``` entry: { main: './src/main.js', styles: './src/styles.css' } ``` ###### webpack.config 新增 loaders 为了适应一些静态资源文件(偏样式方面)的加载, 新增了一系列loaders. 可以看到在`webpack.base.config.js`的`module`里的`rules`, 新增了如下的加载规则和对应的loaders: ``` { test: /\.css$/, exclude: pathUtil.root(baseConfig.dir.src, 'app'), loader: ExtractTextPlugin.extract({ use: ['css-loader'], fallback: ['style-loader'] }) }, { test: /\.css$/, include: pathUtil.root(baseConfig.dir.src, 'app'), loader: ExtractTextPlugin.extract({ use: ['css-loader'], fallback: ['style-loader'] }) }, { test: /\.(png|jpe?g|gif|ico)$/, loader: 'url-loader', options: { limit: 10000, useRelativePath: true, publicPath: './', name: '[name].[ext]' } }, { test: /\.(woff|woff2|svg|ttf|eot)$/, loader: 'file-loader', options: { limit: 10000, useRelativePath: false, publicPath: './', name: '[name].[ext]' } } ``` 前两个规则(rules), 表示分别对应于位于`node_modules`和位于`src/app`文件夹下的所有目录的所有以`.css`结尾的文件. 通过`css-loader`进行加载. > 思考: 这样分开有什么好的意义吗? 第三个规则, 表示在所有entry解析到的文件中, 根据不同的资源文件的后缀, 使用不同的loader. 并且在需要的时候, 可以把他们释放到指定的相对的路径, 亦或是当这个资源文件过小的时候, 以base64编码形式融合在打包好的css/js文件中, 而非独立文件. 第四个规则, 同第三个规则, 但是是用`file-loader`对字体相关的文件进行处理. 这里的第三个和第四个规则, 在加载`bootstrap.css`的过程中, 生效, 并做了如下处理: 在完整的`bootstrap.css`中,有如下一段引入`icon-font`的代码: ``` .... @font-face { font-family: 'Glyphicons Halflings'; src: url('../fonts/glyphicons-halflings-regular.eot'); src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); } .... ``` 在原来位于`node_modules`文件夹下的文件结构时, 此段代码表示他会去读取`'../fonts/glyphicons-halflings-regular.eot'`. 我们来看一下这个`bootstrap/dist`下的文件结构: ``` ├───css │ bootstrap-theme.css │ bootstrap-theme.css.map │ bootstrap-theme.min.css │ bootstrap-theme.min.css.map │ bootstrap.css │ bootstrap.css.map │ bootstrap.min.css │ bootstrap.min.css.map │ ├───fonts │ glyphicons-halflings-regular.eot │ glyphicons-halflings-regular.svg │ glyphicons-halflings-regular.ttf │ glyphicons-halflings-regular.woff │ glyphicons-halflings-regular.woff2 │ └───js bootstrap.js bootstrap.min.js npm.js ``` 因为上面第四个`file-loader`的配置, webpack在进行构建解析的时候, 会把所需要的这些字体文件后缀的文件, 搬到最终 `dist` 文件夹下的根路径. 所以在webpack构建后的路径,我们再来找一下这个`font-face`字段: ``` @font-face { font-family: Glyphicons Halflings; src: url(glyphicons-halflings-regular.eot); src: url(glyphicons-halflings-regular.eot?#iefix) format("embedded-opentype"), url(glyphicons-halflings-regular.woff2) format("woff2"), url(glyphicons-halflings-regular.woff) format("woff"), url(glyphicons-halflings-regular.ttf) format("truetype"), url(glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format("svg") } ``` #### webpack 与 angularjs 视图模板 在上面提及 webpack module rules 的时候, 我们已经看到了不止新增了4条rule. 还有一条 `ng-cache-loader` 的loader. 这个配置的意思是, 对于 非`src`目录下的`index.html`, 其他在项目中被entry 引用的`html`文件, 都会使用 `ng-cache-loader`进行加载, 直接将他变成一个 `angularjs`中的 `view template`. 具体用法, 可以参见上一个项目的 `src/app/routes.js` 的更变: 在上一个项目中, `src/app/routes.js` 大概是这样的: 在 `template` 字段直接进行模板 html内容的声明. ```javascript module.exports = function ($stateProvider) { $stateProvider .state({ name: 'default', url: '', template: '

Hello ITA

' }) .state({ name: 'home', url: '/', template: '

Hello ITA

' }) .state({ name: 'about', url: '/about', template: '

About: This is an ITA Application

' }); }; ``` 使用了`ng-cache-loader`之后, 我们可以通过如下几种方式来引用 模板html文件. 举一种使用方式 : ``` module.exports = function ($stateProvider) { $stateProvider .state({ name: 'login', url: '/login', template: require('../layouts/login/login.html') }) .state({ name: 'register', url: '/register', template: require('../layouts/register/register.html') }) }; ``` #### Webpack的开发时代理中间件 在过往的时候, 在大部分前后端分离开发的项目, 有一个比较蛋疼的地方就是: 每一次前端资源文件更新 都需要将他转移到 后端文件夹对应的目录. `webpack-dev-server`的proxy中间件, 则方便的实现了这些功能(相对于各种实现代理的工具,最重要的是他能够在进行代理的时候,支持websocket). 在刚才预先提供的后台简单项目`backend-springboot`里面, 提供了一个api, 其url为 [http://127.0.0.1:8080/api/v1/validate-json](http://127.0.0.1:8080/api/v1/validate-json) 而现在这个`webpack-gulp-angularjs-boilerplate`, 前端开发时, 默认是监听 5001 端口. 通过在`webpack.dev.config.js`的`devServer`中添加 proxy相关配置, 下面代码表示, 监听开发时端口(5001) 的所有发送到 `/api/*`的http请求, 都转发到 `127.0.0.1:8080`(你的后端服务器监听端口) 那么我们可以在前端开发时,通过访问 [http://127.0.0.1:5001/api/v1/validate-json](http://127.0.0.1:5001/api/v1/validate-json) 来实现代理转发的功能. ``` proxy: { '/api': { target: 'http://127.0.0.1:8080/', secure: false, ws: true } } ``` ### 总结 此项目可以用作Simple Project的一个前端方面的手脚架, 他遵循并通过现有的工具实现了一些前端工程方面常见的较佳实践. 但是前端工程化依然发展的很快, 此项目仅仅以`angularjs + commonjs语法`作为一个例子. 可以说为日后将要遇到的`Angular`,`Vue`,`React`等更先进的前端框架, 亦或是更高级的构建工具, 提供了一个基本的开发思维与工具升级实践. 希望在了解这个进化过程的基础上, 在遇到新的前端项目时候, 能够快速了解其构件流程, 举一反三, 快速上手.