{"id":17126279,"url":"https://github.com/aquariuslt/webpack-revolution","last_synced_at":"2025-04-13T06:27:27.273Z","repository":{"id":68995259,"uuid":"91669207","full_name":"aquariuslt/webpack-revolution","owner":"aquariuslt","description":"Webpack-Revolution","archived":false,"fork":false,"pushed_at":"2023-12-15T17:31:10.000Z","size":478,"stargazers_count":9,"open_issues_count":1,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-26T23:03:10.952Z","etag":null,"topics":["angularjs","gulp","webpack","webpack2"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aquariuslt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-05-18T08:34:59.000Z","updated_at":"2018-09-07T15:51:04.000Z","dependencies_parsed_at":null,"dependency_job_id":"eb7fdc87-a239-4465-a7cd-cae4af3372ae","html_url":"https://github.com/aquariuslt/webpack-revolution","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aquariuslt%2Fwebpack-revolution","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aquariuslt%2Fwebpack-revolution/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aquariuslt%2Fwebpack-revolution/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aquariuslt%2Fwebpack-revolution/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aquariuslt","download_url":"https://codeload.github.com/aquariuslt/webpack-revolution/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248673191,"owners_count":21143449,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angularjs","gulp","webpack","webpack2"],"created_at":"2024-10-14T18:47:31.044Z","updated_at":"2025-04-13T06:27:27.248Z","avatar_url":"https://github.com/aquariuslt.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Webpack Revolution\n\n\n目录:\n- [Pure AngularJS Project](https://github.com/Aquariuslt/Webpack-Revolution/tree/master/pure-angularjs-project)\n- [Pure CommonJS Project](https://github.com/Aquariuslt/Webpack-Revolution/tree/master/pure-commonjs-project)\n- [Simple-Webpack-AngularJS](https://github.com/Aquariuslt/Webpack-Revolution/tree/master/simple-webpack-angularjs)\n- [Webpack-Gulp-AngularJS](https://github.com/Aquariuslt/Webpack-Revolution/tree/master/webpack-gulp-angularjs)\n- [Webpack-Gulp-AngularJS-Boilerplate](https://github.com/Aquariuslt/Webpack-Revolution/tree/master/webpack-gulp-angularjs-boilerplate)\n\n\n## 前言\n\n该代码示例描述了一个普通的前端项目进化到使用Webpack + Gulp 管理构建流的过程.\n\n提供了一个现代化JavaScript工程化项目的模板与思路.\n\n预备知识:\n- 一些基础的`AngularJS`知识\n- 一些`angular-ui-router`的知识\n- `Webpack`的作用与简介\n- `Gulp`的作用与简介\n\n\n\n[代码下载](https://github.com/Aquariuslt/Webpack-Revolution)\n\n![Project-Structure](https://ooo.0o0.ooo/2017/05/21/59210e605f1c3.png)\n\n示例项目里面包含了若干个子项目,以上图红圈内的几个项目文件夹为示例:\n从上往下依次是: \n\n1. 最原始的AngularJS项目\n2. 使用Webpack构建的,以CommonJS方式编写的JS项目\n3. 结合1,2的项目,使用Webpack,以CommonJS编写的AngularJS项目\n5. 在3的基础上,使用Gulp任务流进行Webpack构建的一个AngularJS项目\n4. 在5的基础上,将原来的AngularJS项目拆分成模块化,并添加CSS构建等模块\n\n\n\u003e P.S.为什么上面的顺序5和4会对调?因为在Github的网页上面显示的顺序不太对,按照字典序的排序 应该 `webpack-gulp-angularjs` 会在 `webpack-gulp-angularjs-boilerplate` 之前\n\n\n接下来请跟着文档的步骤,下载项目自己动手运行.\n\n\n运行需求环境:\ngit \u003e=3  \nnpm \u003e=3   \nnode \u003e=6    \n\n\n## Getting Start\n\n### 把项目下载到本地\n```bash\ngit clone https://github.com/Aquariuslt/Webpack-Revolution.git\ncd Webpack-Revolution\n```\n\n## Pure-AngularJS-Project\n\n### 安装项目依赖\n```\ncd pure-angularjs-project\nnpm install\n```\n\n### 项目说明\n项目的文件夹目录大概如下\n```\nMacbook:pure-angularjs-project Aquariuslt$ tree\n.\n├── README.md\n├── package.json\n├── server.js\n├── static\n│   ├── favicon.ico\n│   ├── index.html\n│   └── js\n│       ├── app\n│       │   ├── app.js\n│       │   └── routes.js\n│       └── vendor\n│           ├── angular-ui-router.js\n│           └── angular.js\n\n```\n\n这是一个很原始的JavaScript项目,通过手动在`static/index.html`中添加JS,CSS文件的引用,接着使用`express`将`static`这个文件夹下的内容当成静态的前端资源文件提供出来.\n\n### 运行项目\n\n运行`npm start` 之后,我们可以在浏览器的[http://127.0.0.1:3000](http://127.0.0.1:3000) 看到效果\n\n![pure-angularjs-project-runtime-min.gif](https://ooo.0o0.ooo/2017/05/21/592143245b71e.gif)\n\n### 代码说明\n1.static/index.html\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\" ng-app=\"ita-app\"\u003e\n\u003chead\u003e\n  \u003ctitle\u003ePure AngularJS Application\u003c/title\u003e\n  \u003cbase href=\"/#!/\"\u003e\n  \u003cmeta charset=\"UTF-8\"\u003e\n  \u003clink rel=\"icon\" href=\"favicon.ico\" type=\"image/x-icon\"\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003c!-- Header Area --\u003e\n\u003ch2\u003ePure AngularJS Application\u003c/h2\u003e\n\u003ca ui-sref=\"home\"\u003eHome\u003c/a\u003e\n\u003ca ui-sref=\"about\"\u003eAbout\u003c/a\u003e\n\u003c!-- Router View Area --\u003e\n\u003cui-view\u003e\u003c/ui-view\u003e\n\n\n\u003c!-- Vendor JS Files --\u003e\n\u003cscript type=\"text/javascript\" src=\"js/vendor/angular.js\"\u003e\u003c/script\u003e\n\u003cscript type=\"text/javascript\" src=\"js/vendor/angular-ui-router.js\"\u003e\u003c/script\u003e\n\n\u003c!-- Own Application JS Files --\u003e\n\u003cscript type=\"text/javascript\" src=\"js/app/app.js\"\u003e\u003c/script\u003e\n\u003cscript type=\"text/javascript\" src=\"js/app/routes.js\"\u003e\u003c/script\u003e\n\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n负责引入`angular.js`,`angular-ui-router.js`\n以及项目开发者自行编写的`app.js`与`routes.js`\n\n2.static/app/app.js\n```javascript\n(function () {\n  angular.module('ita-app',\n    ['ui.router']\n  )\n})();\n```\n\n此处注册一个angular的module,叫做`ita-app`\n\n3.static/app/routes.js\n```javascript\n(function () {\n  angular.module('ita-app')\n    .config(function ($stateProvider) {\n      $stateProvider\n        .state({\n          name: 'default',\n          url: '',\n          template: ' \u003ch3\u003eHello ITA\u003c/h3\u003e'\n        })\n        .state({\n          name: 'home',\n          url: '/',\n          template: ' \u003ch3\u003eHello ITA\u003c/h3\u003e'\n        })\n        .state({\n          name: 'about',\n          url: '/about',\n          template: '\u003ch3\u003eAbout: This is an ITA Application\u003c/h3\u003e'\n        });\n    });\n})();\n```\n\n此处声明`ui-router`的三个路由的url:\n分别是`/`, `/about`\n\n4.server.js\n```javascript\nvar express = require('express');\n\nvar app = express();\n\napp.use('/', express.static('static'));\n\napp.listen(3000);\n```\n此处表示使用express 监听3000端口,并以项目文件夹下的`static`作为静态资源的文件来提供服务.\n\n### 总结\n如同上面的运行时的GIF所示.\n在不同的路由情况下,页面展现的内容不一样.\n\n相信这个内容,在接触了Node.js的`express.js`\n与`angular.js` 基本知识之后都能很容易的理解,简直是小菜一碟!\n\n\n\n## Pure-CommonJS-Project\n\n在了解了前面一个课程之后,我们开始接触最基础的一个利用Webpack打包的CommonJS的项目.\n\n该样例的目的有两个:\n\n其一是Webpack的简单Demo.\n\n其二是使用Node.js的CommonJS语法进行JavaScript模块的导入导出.\n\n说明流程是 先运行 后解释 先运行后解释!\n\n### 安装项目依赖\n```bash\ncd pure-commonjs-project\nnpm install\n```\n\n### 项目说明\n\n项目目录大以及说明概如下:\n```\n├── README.md\n├── package.json\n├── server.js\n├── src\n│   ├── app\n│   │   ├── bar.js\t\t\t\t\t\t\t\t\t\t\t--模块bar\n│   │   └── foo.js\t\t\t\t\t\t\t\t\t\t\t--模块foo\n│   ├── index.html\t\t\t\t\t\t\t\t\t\t    --默认的index.html\n│   └── main.js\t\t\t\t\t\t\t\t\t\t\t\t--项目的前端入口JavaScript文件\n├── webpack.config.js\t\t\t\t\t\t\t\t\t    --Webpack约定的默认配置文件名\n```\n\n### 运行项目\n```bash\nnpm start\n```\n\n![pure-commonjs-project-start.png](https://ooo.0o0.ooo/2017/05/21/59214b2da94f7.png)\n\n命令行里面会出现webpack打包的输出\n之后在浏览器查看[http://127.0.0.1:3001](http://127.0.0.1:3001)\n\n应该如下图般显示:\n![pure-commonjs-prject-browser.png](https://ooo.0o0.ooo/2017/05/21/59214c1125273.png)\n\n好,自己动手的过程到此告一段落.\n请继续阅读文档下面的部分,看看中间到底发生了什么.\n\n\n### 过程简介\n在运行`npm start`之后,到底经过了什么样的操作呢?\n大概是如下一个流程:\n\n1.`npm start`命令,先指向了`package.json`里面`scripts`部分的`start`.\n以`package.json`文件为例:`npm start`指向了一个`webpack \u0026\u0026 node server.js`的命令.\n\n```json\n{\n  \"name\": \"pure-commonjs-project\",\n  \"version\": \"1.0.0\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"start\": \"webpack \u0026\u0026 node server.js\"      \n  },\n  \"dependencies\": {\n    \"express\": \"^4.15.3\"\n  },\n  \"devDependencies\": {\n    \"html-webpack-plugin\": \"^2.28.0\",\n    \"webpack\": \"^2.5.1\"\n  }\n}\n```\n\n该命令表示,当全局安装了webpack,或者项目的`node_modules/.bin/`下面有webpack的可执行文件的时候.可以通过内置的命令`webpack`来执行打包的功能.\n\n当执行完命令`webpack`之后,开始执行`node server.js`这一句命令.\n\n使用`express.js`监听某个端口(3001),对某个文件夹(public)进行静态资源的监控.\n\n讲到这里,相信大家已经大概知道\n1.`npm start` 实际调用的其他命令\n2.`webpack`这个命令,会执行打包构建的工作,把构建好的文件输出到指定的文件夹.\n\n`webpack`命令的详细工作流程,在接下来的部分会讲到.\n\n### 代码说明\n在逐个代码文件进行说明的时候,可能发现整个项目的文件夹名字都跟第一个项目`pure-angularjs-project`有所不同了.\n\n遵循主流的JavaScript前端项目的约定,我们把\n项目的`index.html`和其他源代码的部分都放在`src`文件夹下.\n将最后编译/构建/打包的文件都放在`public`文件夹下.\n\n\u003e 对于`public`文件夹这个命名,流行的别名有很多,这里取`public`为例子\n\u003e 还有一些其他流行的别名都可以使用:\n\u003e 譬如`static`(意为静态资源文件,第一个项目就是用这个来命名).\n\u003e 又如`dist`(意为distribution)\n\u003e 这些命名地位和意义相等,没有争论的必要,都可以用\n\n\n对于代码说明, 我们先看`webpack.config.js`这个webpack的配置文件.\n再对`src`下的源代码文件做逐一说明.\n\n\n1.webpack.config.js\n\n刚刚在执行`npm start`命令的时候,有些同学可能有困惑:\n\"我只执行了`webpack`这个命令,他怎么就帮我全部打包到`public`文件夹了?\"\n\n其实`webpack`命令执行的时候,按照其官方文档提供的说明和*约定*,在不指定任何参数的时候,默认会去读取项目目录下的`webpack.config.js`\n\n所以使用纯的命令`webpack`,就相当于执行`webpack --conf webpack.config.js`.\n去读取该配置文件进行打包.\n\n现在我们来看一下`webpack.config.js`的内容\n\n```javascript\nvar path = require('path');\nvar webpack = require('webpack');\n\nvar HtmlWebpackPlugin = require('html-webpack-plugin');\n\n\nmodule.exports = {\n  entry: {\n    main: './src/main.js'\n  },\n  output: {\n    path: path.resolve('public'),\n    publicPath: '',\n    filename: '[name].bundle.js',\n    chunkFilename: '[id].[hash].chunk.js'\n  },\n  resolve: {\n    extensions: ['.js']\n  },\n  plugins: [\n    new HtmlWebpackPlugin({\n      template: 'src/index.html'\n    })\n  ]\n};\n```\n\n需要注意的几个部分是:\n```javascript\nentry: {\n  main: './src/main.js'\n}\n```\n`entry`部分说明了webpack将以`src/main.js`为打包的入口文件.\n将其require的层层依赖最后都打包到一个文件里面.\n\n```javascript\noutput: {\n  path: path.resolve('public'),\n  publicPath: '',\n  filename: '[name].bundle.js',\n  chunkFilename: '[id].[hash].chunk.js'\n}\n```\n`output`部分说明了webpack读取入口文件之后,打包好的项目代码,以怎样的形式\n输出.\n\n在上面的例子中\n`path`表示把所有的输出文件都放到`public`文件夹中.  \n`filename`表示输出的`javascript`文件需要如何命名,这里的意思是,如果入口文件名为`main.js`,根据webpack对`[name].bundle.js`的格式化处理,将会输出成`main.bundle.js`\n\n剩余的`publicPath`,`chunkFilename`目前暂时不用关心.\n\n```javascript\nplugins: [\n  new HtmlWebpackPlugin({\n    template: 'src/index.html'\n  })\n]\n```\nwebpack有很多插件(包括官方提供的,和流行的第三方插件).\n在配置文件的`plugins`字段描述了按生命的顺序加载并使用该插件对输出的文件进行处理.\n\n里面用到的`HtmlWebpackPlugin`是一个很常用的插件,\n在这里的意思大概是,他会以`src/index.html`作为模板,最后把输出的javascript,css等资源文件的链接插入到`index.html`合适的地方.\n\n2.main.js   \n\n```\nrequire('./app/foo');\nrequire('./app/bar');\n\nconsole.log('load main.js');\ndocument.write('\u003ch1\u003eLoad main.js\u003ch1\u003e');\nmodule.exports = {};\n```\n\nmain.js作为入口文件,他希望做到的是先加载`foo.js`与`bar.js`\n接着执行自己的内容,在控制台输出`load main.js`\n接着在body里面插入一条`h1`的标签.\n\n3.app/foo.js 与 app/bar.js  \n\nfoo.js\n```javascript\nconsole.log('load foo.js');\ndocument.write('\u003ch1\u003eLoad foo.js\u003ch1\u003e');\nmodule.exports = {};\n```\n\nbar.js\n```javascript\nconsole.log('load bar.js');\ndocument.write('\u003ch1\u003eLoad bar.js\u003ch1\u003e');\nmodule.exports = {};\n```\nfoo.js 与 bar.js 如字面意思.\n\n4.index.html  \n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n  \u003cmeta charset=\"UTF-8\"\u003e\n  \u003ctitle\u003eCommonJS Project\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\n\u003c!-- There is no any js require here ! --\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n需要注意的是,这里的`index.html`文件是没有任何引用javascript,css文件的显式声明的.\n\n这就是上面提及的`webpack.config.js`里面的`HtmlWebpackPlugin`所做的工作!\n可以对比一下作为原始模板的`src/index.html`与构建之后的`public/index.html`:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n  \u003cmeta charset=\"UTF-8\"\u003e\n  \u003ctitle\u003eCommonJS Project\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\n\u003c!-- There is no any js require here ! --\u003e\n\u003cscript type=\"text/javascript\" src=\"main.bundle.js\"\u003e\u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nwebpack 在构建过程中插入了`main.bundle.js`的引用!\n\n### 思考\n以CommonJS的语法进行前端JavaScript代码的编写.\n模块加载顺序,与直接内嵌在html文件中有什么不同?\n\n如下图,我们把对`src/app/foo.js`的引用注释掉,再执行`npm start`.\n\n构建后的代码有什么不同?浏览器的内容跟浏览器控制台输出的内容有什么不同?\n\n```javascript\n//require('./app/foo');\nrequire('./app/bar');\n\nconsole.log('load main.js');\ndocument.write('\u003ch1\u003eLoad main.js\u003ch1\u003e');\nmodule.exports = {};\n```\n\n### 总结\n\n通过这个普通的Webpack的Demo.\n\n你应该体会到:\n\n1. Webpack 构建打包的基础过程\n2. 开始学习并习惯以CommonJS形式编写前端的JavaScript代码(这里的CommonJS形式并非JavaScript项目的模块化概念!)\n\n并可能触发一些思考:\n\n- 如何与`angular.js`,`jquery`甚至其他主流的javascript框架结合使用?\n- 如何对webpack的配置进行根据不同环境的可配置化?(本地开发,生产环境,测试环境)\n...... \n\n\n\n\n\n## Simple-Webpack-AngularJS\n在了解完前面两个项目的代码之后.\n你见识到了:\n\n- 一个最基础的可运行的`angularjs`项目\n- 一个最基础的用`webpack`构建的js项目\n\n那么如何结合两者,变成一个 用`webpack`构建的`angularjs`项目呢?\n\n`simple-webpack-angularjs` 该项目的内容,即使一个结合第一和第二个项目代码样例而成的,用`webpack`构建的`angularjs`项目样例.\n\n在展现出来的效果看,跟`pure-angularjs-project`的效果是一样的.\n\n\u003e 该项目样例在尽量不修改大量配置的情况下,实现了所需要的功能\n\u003e 实际上,该项目的配置,结构 还离 功能齐全的 可配置化的实际项目的结构\n\u003e 有稍大的差距.还不能作为一个正式的手脚架使用.\n\u003e 不过作为学习项目演变过程的样例,希望同学们能够从中汲取到一些关于webpack的知识.\n\n### 安装项目依赖\n```bash\ncd simple-webpack-angularjs\nnpm install\n```\n\n### 项目说明\n项目的结构大概如下\n```\n├── README.md\n├── package.json\n├── server.js\n├── src\n│   ├── app\n│   │   └── routes.js\n│   ├── favicon.ico\n│   ├── index.html\n│   └── main.js\n├── webpack.config.js\n\n```\n\n结构与`pure-common-js`大概相同.\n\n其中需要说明的是:\n`src/app/routes.js` 等同于 第一个项目的 `static/js/app/routes.js`\n\n`src/main.js`作为入口的js文件,功能上等同于第一个项目的`static/js/app/app.js`\n\n### 运行项目\n```bash\nnpm start\n```\n\n命令行里面会出现webpack打包的输出\n之后在浏览器查看[http://127.0.0.1:4000](http://127.0.0.1:4000)\n\n\u003e 为了使多个项目能够同时运行方便比较,所以端口号分别取了3000,3001,4000端口\n\n![simple-webpack-angularjs-min.gif](https://ooo.0o0.ooo/2017/05/21/592175cea4292.gif)\n\n### 代码说明\n主要查看的是 `src/main.js`,`src/app/routes.js`\n\n1.main.js\n```javascript\nvar angular = require('angular');\nvar uirouter = require('@uirouter/angularjs');\n\n// import your routes config\nvar appRoutes = require('./app/routes');\n\nmodule.exports = angular.module('ita-app', [\n  'ui.router'\n])\n  .config(appRoutes)\n;\n```\n\n此时回顾一下`pure-angularjs-project`的`app.js`\n\n```javascript\n(function () {\n  angular.module('ita-app',\n    ['ui.router']\n  )\n})();\n```\n\n我们可以看出`app.js` 里面只声明了`ita-app`的模块和对`ui.router`的依赖,没有声明route.\n\n而在`main.js`里面:\n先用`require('angular')`,`require('@uirouter/angularjs')`\n对第三方的`angularjs`,`angular-ui-router`进行引用.\n\n接着再声明一个新的叫`ita-app`的模块.\n并且将该模块下声明的route都加载到这里\n\n2.app/routes.js\n```javascript\nmodule.exports = function ($stateProvider) {\n  $stateProvider\n    .state({\n      name: 'default',\n      url: '',\n      template: ' \u003ch3\u003eHello ITA\u003c/h3\u003e'\n    })\n    .state({\n      name: 'home',\n      url: '/',\n      template: ' \u003ch3\u003eHello ITA\u003c/h3\u003e'\n    })\n    .state({\n      name: 'about',\n      url: '/about',\n      template: '\u003ch3\u003eAbout: This is an ITA Application\u003c/h3\u003e'\n    });\n};\n```\n\n此时在回顾一下`pure-angularjs-project`的`route.js`\n```javascript\n(function () {\n  angular.module('ita-app')\n    .config(function ($stateProvider) {\n      $stateProvider\n        .state({\n          name: 'default',\n          url: '',\n          template: ' \u003ch3\u003eHello ITA\u003c/h3\u003e'\n        })\n        .state({\n          name: 'home',\n          url: '/',\n          template: ' \u003ch3\u003eHello ITA\u003c/h3\u003e'\n        })\n        .state({\n          name: 'about',\n          url: '/about',\n          template: '\u003ch3\u003eAbout: This is an ITA Application\u003c/h3\u003e'\n        });\n    });\n})();\n```\n\n与`pure-angularjs-project`  的 `routes.js`相比\n主体功能是完全一样的,只需要export出去,在模块声明的地方用\n`angular.module(moduleName,[]).config(${export的部分})`即可\n\n\n实际运行效果是一样的.\n\n\u003e P.S. 找个在读的小伙伴测了下 貌似对上面这句不理解.\n\u003e 可以参考下面两个图,是相等的:\n\n![1.png](https://ooo.0o0.ooo/2017/05/21/592187834c401.png)\n![2.png](https://ooo.0o0.ooo/2017/05/21/5921878345d59.png)\n\n\n\n### 思考\n1. 查看生成的`public/main.bundle.js`\n是否发现`angular.js`的源代码和`@uirouter/angularjs`的源代码已经包含在里面?\n是否应该将业务代码与第三方依赖代码分开储存?\n项目协作人数越来越多的时候,如何利用CommonJS的模块语法,实现AngularJS工程的模块化?\n打包到一起的时候,如何在浏览器中方便的调试业务代码?\n部署上生产环境的时候,是否需要制定不同环境的配置,譬如生产环境JS压缩等操作?\n\n### 总结\n该项目提供了一个使用angularjs,利用CommonJS语法组织工程代码,使用Webpack进行构建打包的一个样例.\n\n\n\n## Webpack-Gulp-AngularJS\n通过基本的前端项目工程化的介绍,\n我们大概了解了:\n- Webpack的简介\n- Gulp的简介与定位\n\n通过之前的几个样例代码,\n我们大概了解了:\n- Webpack的基本使用方法\n- Webpack的基本配置\n- 使用CommonJS 编写原来的AngularJS项目\n\n请注意回顾到里面样例代码的演变形式,\n因为这一章节,主要的改动是引入gulp来使得项目构建流程化.\n\n如果在阅读文档并且动手操作之后,还不了解前面1,2,3 三个部分的演变过程请将疑问提到[issues](https://github.com/Aquariuslt/Webpack-Revolution/issues)里面.\n会根据情况进行文档的补充.\n\n\n如果没有足够的理解,那么可能在阅读这一章节的时候就可能变成以下这个情况:\n\n![算术入门.jpg](https://ooo.0o0.ooo/2017/05/23/5923c9999692c.jpg)\n\n\n如果顺利的话,在这一章节,我们将了解以下的部分内容:\n- 划分不同环境的Webpack构建配置\n- Gulp与常见Gulp插件的一些介绍与使用\n- Webpack与Gulp的结合使用\n- Webpack-Dev-Server 带来的开发体验的巨大提升\n\n\n涉及的项目文件更变有点多.\n\n中间有任何不明白的地方 请立刻提issue, 以便做出修改 达到更好的教学效果.谢谢~\n\n### 安装项目依赖\n```bash\ncd webpack-gulp-angularjs\nnpm install\n```\n\n\n### 项目说明\n之前的项目里面,都是先运行,再解释.\n\n这个章节的流程不一样:\n\n1. 先讲述一些应用场景,了解背景\n2. 再讲述改项目样例参考的灵感来源\n3. 再介绍项目改变的部分\n4. 介绍新增的部分的工具以及example的说明\n\n\n##### 生产环境与开发环境的配置分离\n无论是大小项目,可能都需要区分本地开发环境(Development),生产环境(Production/Release).\n规模稍大以致能够更细分成本地开发环境,测试环境,集成开发环境,预生产环境 等更多不同的环境.\n\n在不同的环境里面,项目展现出的各种配置可能不一样.\n\n以JavaScript前端项目为例子.\n可能不同环境的配置是不一样的,展现出来的区分在于:\n\n本地开发环境: \n- 浏览器展现出的JavaScript代码,方便调试,定位问题.CSS,JS不会经过压缩,混淆,合并.\n- 控制台输出全部级别的日志.\n- API请求连接到的是本地/测试环境的后台服务器\n- ....\n\n生产环境:\n- 为了符合最佳网站实践,浏览器加载页面时候的静态资源文件大小尽量小,请求数尽量少\n- 控制台也不输出调试日志.\n- ....\n\n\n\n\n因此,根据此项目的情况,我们会将使用webpack构建的过程,分成本地开发环境,与生产环境两种配置.\n\n在下文的文件说明中,会详细提及他们之间的变化.\n\n现在大概对不同环境下,对应不同构建配置的必要性有个基本的了解了吧.\n\n\n##### 构建任务流\n如果之前接触过maven,或者gradle,可以发现:\n\n在J2EE项目中,通常本地构建会有一些构建任务\n使用maven的话\n使用命令:\n```bash\nmvn clean\nmvn package\n```\n抑或是使用gradle:\n```bash\ngradle clean\ngradle build\n```\n\n这些都可以理解成包管理器/构建工具内置的任务流之一.\n\n`xxx clean`的意思就是清除(删除)所有构建生成的文件.\n\n`xxx package`的意思是编译并打包构建好的文件.\n\n转换到node.js的情景:\n\n既然npm本身不会带有这方面的内置的任务流(对于项目构建生成的文件,也没有约定在某一个/几个目录,比如maven的`/target`,gralde的`/build`).\n\n所以一般是使用主流的任务流工具:gulp或者grunt 来代替完成这部分的工作.\n\n\n参考过大部分主流的前端项目:\n- Angular4团队 `@angular/cli`内置的webpack任务流\n- `vue-cli`中使用webpack构建的任务流\n- 其他主流项目\n\n从这些项目中了解到的一些任务流的命名.\n\u003e P.S. 仅仅是希望大家能接受这种命名,不是我突发奇想,胡乱想出来的一些命名\n\n如果使用gulp作为任务流工具,我们根据不同环境拆分配置的时候.\n可能会有以下的任务流:\n\n- gulp clean       清除默认的构建中生成的文件夹\n- gulp build        构建用于部署的,生产环境用到的文件\n- gulp serve        本地开发时,用于提供web服务的命令\n- gulp test            执行单元测试,\n\n\n好,大概了解了这章节的样例代码所涉及的概念.\n接下来就开始描述项目结构的更变吧.\n\n##### 项目结构\n\n在实现与样例`pure-angularjs-project`,`simple-webpack-angularjs`相同的效果的情况下:\n项目的结构大概如下:\n```\n.\n├── README.md\n├── gulpfile.js\n├── package.json\n├── src\n│   ├── app\n│   │   └── routes.js\n│   ├── favicon.ico\n│   ├── index.html\n│   └── main.js\n├── tasks\n│   ├── build.js\n│   ├── clean.js\n│   ├── config\n│   │   ├── base.config.js\n│   │   ├── webpack.base.config.js\n│   │   ├── webpack.dev.config.js\n│   │   └── webpack.prod.config.js\n│   ├── serve.js\n│   └── util\n│       └── path-util.js\n└── yarn.lock\n\n```\n\n\n项目结构更变概括:\n1. 在webpack的配置方面,为了拆分本地开发环境,我们将原来的位于项目根文件夹的`webpack.config.js`拆分成以下形式:\n\n![webpack-config-dependencies.png](https://ooo.0o0.ooo/2017/05/23/5923f187ea0c8.png)\n\n\u003e P.S. 注意加粗黄线的部分,才是要注意的地方\n\n现在把`webpack.config.js`\n拆分成`webpack.base.config.js`,`webpack.dev.config.js`,`webpack.prod.config.js`三个文件\n\n其中`webpack.dev.config`是基于`webpack.base.config`的开发运行时配置\n\n而`webpack.prod.config.js`是基于`webpack.base.config`的生产环境构建配置\n\n因为中间配置的内容比较复杂,但项目技术框架选型定下之后(目前样例选择的是AngularJS),三个以webpack开头的配置文件改动频率相当小.\n\n因此我把改动频率较大,只需开发者关心且修改频率可能很大的部分抽取到`base.config.js`里面.\n\n等下会说明该部分内容.\n\n2. 使用gulp进行构建任务流之后, 我们将通过 gulp 调用webpack进行前端代码的构建任务.\n\n因此, webpack的配置文件,被移动到`tasks/config`文件夹中\n\n我们将通过 `npm run dev`,`npm run build`,`npm run clean` 三个命令分别调用\n`gulp serve`,`gulp build`,`gulp clean`.\n\n根据 gulp 的约定, 执行gulp命令的时候,默认会读取 项目根目录下的 `gulpfile.js`加载task列表.\n\n所以我们能看到`gulpfile.js`里面的内容,是导入`/tasks/`文件夹下的三个 tasks :`build`,`clean`,`serve`\n\n```javascript\nrequire('./tasks/clean');\nrequire('./tasks/build');\nrequire('./tasks/serve');\n```\n\n项目文件更变说明到此结束.\n下面开始运行项目,先运行,后面在\u003cb\u003e代码说明\u003c/b\u003e小章节解释每份配置的内容.\n\n### 运行项目\n现在项目有三种tasks可以执行:\n- npm run clean: 表示清除项目构建生成的文件夹\n- npm run build: 该task会先执行上面的`clean`操作,再以webpack生产环境配置,构建出生产环境需要用的静态资源文件\n- npm run dev: 该task会启动一个`webpack-dev-server`,目前默认监听`5001`端口. 以webpack开发环境配置构建,可以将源代码内容的更变实时反映到浏览器上.\n\n\n下面我们先按`build`,`clean`,`dev`这种顺序执行一次\n\n\n1. build\n```bash\nnpm run build\n```\n\n可以看到 执行 `gulp`的task的时候的一些输出\n\n```\n[09:14:53] Starting 'build'...\n[09:14:53] Starting 'clean'...\n[09:14:53] Starting 'clean:build'...\n[09:14:53] Deleting build folder\n[09:14:53] Starting 'clean:dist'...\n[09:14:53] Deleting dist folder\n[09:14:53] Finished 'clean:build' after 14 ms\n[09:14:53] Finished 'clean:dist' after 7.12 ms\n[09:14:53] Finished 'clean' after 17 ms\n[09:14:53] Starting 'webpack'...\n[09:14:53] Webpack building.\n[09:14:59] Hash: 15ec065050c6b4d08cd6\nVersion: webpack 2.5.1\nTime: 6444ms\n                             Asset       Size  Chunks                    Chunk Names\n      main.2949cd4c297786231109.js  425 bytes       0  [emitted]         main\n    vendor.f7682f3c276a26fc48f2.js     301 kB       1  [emitted]  [big]  vendor\n  main.2949cd4c297786231109.js.map    2.69 kB       0  [emitted]         main\nvendor.f7682f3c276a26fc48f2.js.map    3.96 MB       1  [emitted]         vendor\n                       favicon.ico    5.43 kB          [emitted]\n                        index.html  534 bytes          [emitted]\nchunk    {0} main.2949cd4c297786231109.js, main.2949cd4c297786231109.js.map (main) 711 bytes {1} [initial]\n[rendered]\n   [59] ./src/app/routes.js 438 bytes {0} [built]\n   [89] ./src/main.js 273 bytes {0} [built]\nchunk    {1} vendor.f7682f3c276a26fc48f2.js, vendor.f7682f3c276a26fc48f2.js.map (vendor) 1.7 MB [entry] [re\nndered]\n    [4] ./~/@uirouter/core/lib/index.js 674 bytes {1} [built]\n   [22] ./~/angular/index.js 48 bytes {1} [built]\n   [23] ./~/@uirouter/angularjs/lib/services.js 6.36 kB {1} [built]\n   [24] ./~/@uirouter/angularjs/lib/statebuilders/views.js 5.57 kB {1} [built]\n   [31] ./~/@uirouter/angularjs/lib/stateProvider.js 6.14 kB {1} [built]\n   [32] ./~/@uirouter/angularjs/lib/urlRouterProvider.js 7.66 kB {1} [built]\n   [33] ./~/@uirouter/core/lib/globals.js 1.18 kB {1} [built]\n   [58] ./~/@uirouter/angularjs/lib/index.js 721 bytes {1} [built]\n   [60] ./~/@uirouter/angularjs/lib/directives/stateDirectives.js 24.4 kB {1} [built]\n   [61] ./~/@uirouter/angularjs/lib/directives/viewDirective.js 15.9 kB {1} [built]\n   [62] ./~/@uirouter/angularjs/lib/injectables.js 12.9 kB {1} [built]\n   [64] ./~/@uirouter/angularjs/lib/stateFilters.js 1.51 kB {1} [built]\n   [67] ./~/@uirouter/angularjs/lib/viewScroll.js 793 bytes {1} [built]\n   [83] ./~/@uirouter/core/lib/url/index.js 385 bytes {1} [built]\n   [88] ./~/angular/angular.js 1.25 MB {1} [built]\n     + 73 hidden modules\nChild html-webpack-plugin for \"index.html\":\n         Asset    Size  Chunks  Chunk Names\n    index.html  545 kB       0\n    chunk    {0} index.html 541 kB [entry] [rendered]\n        [0] ./~/lodash/lodash.js 540 kB {0} [built]\n        [1] ./~/html-webpack-plugin/lib/loader.js!./src/index.html 817 bytes {0} [built]\n        [2] (webpack)/buildin/global.js 509 bytes {0} [built]\n        [3] (webpack)/buildin/module.js 517 bytes {0} [built]\n[09:14:59] Webpack build done\n[09:14:59] Finished 'webpack' after 6.52 s\n[09:14:59] Finished 'build' after 6.54 s\n\n```\n\n之后查看生成的`public`文件夹\n\n会发现有以下的文件:\n```\nfavicon.ico\nindex.html\nmain.2949cd4c297786231109.js\nmain.2949cd4c297786231109.js.map\nvendor.f7682f3c276a26fc48f2.js\nvendor.f7682f3c276a26fc48f2.js.map\n```\n\n`main.2949cd4c297786231109.js`是压缩后的以`src/main.js`为入口的,不包括`node_modules`里面代码引用的构建出来的代码.\n\n`vendor.f7682f3c276a26fc48f2.js`是压缩以后的,源代码中引用到的位于`node_modules`里面的代码. 这里包括了 `node_modules/angular/angular.js`,`node_modules/@uirouter/angularjs`\n\n`main.2949cd4c297786231109.js.map`,`vendor.f7682f3c276a26fc48f2.js.map`\n是前面的两个js文件的`source map`文件.\n作为生产环境反向追踪源代码的手段.(目前只有Chrome支持)\n\n\u003e P.S. 因为webpack生产环境的配置里面output格式是`[name].[chunkhash].js`.\n\u003e 所以中间的一串字符串是一个hash值,每次相同的源代码只会生成相同的chunkhash值\n\n\n2. clean\n```\nnpm run clean\n```\n\n之后你会发现 `public` 文件夹已被删除\n\n\n3. dev\n```\nnpm run dev\n```\n当看到terminal输出`webpack: Compiled successfully`\n的时候,就可以打开浏览器 [http://127.0.0.1:5001](http://127.0.0.1:5001)\n\n同时请打开浏览器的console观察变化.\n\n此时:\n我们把项目源代码的编辑器,与浏览器分别置于整个电脑桌面的左右两边.\n\n在编辑器内打开`src/index.html`并尝试做出一些修改,譬如把`\u003ctitle\u003eSimple Webpack Application\u003c/title\u003e`修改成`\u003ctitle\u003eNot Simple Webpack Application\u003c/title\u003e`.\n\n同时观察浏览器的变化,就能看到浏览器立刻自动刷新并且反映出了结果.\n我们也可以修改`src/app/routes.js`里面的`home` state的template.\n\n浏览器也能够自动刷新出效果!\n\n这就是`webpack-dev-server`的作用之一.\n\n### 代码说明 \n\n\n`tasks/util/path-util.js`\n\n内容:\n\n```javascript\nvar path = require('path');\n\nconst _root = path.resolve(__dirname, '../..');\n\n\nfunction root(args) {\n  args = Array.prototype.slice.call(arguments, 0);\n  return path.join.apply(path, [_root].concat(args));\n}\n\n\nmodule.exports.root = root;\n```\n\n说明:\n\n有个必要说明的是这个`path-util.js`\n\nwebpack的配置里面,\n有一个容易跌坑的地方,便是路径的表示形式.\n\n有一些路径的表示形式是根目录的相对路径,如`./src/main.js`.\n\n有一些路径的表示形式则是配置文件当前路径的相对路径,譬如各种loaders的覆盖路径.\n\n所以这个path-util 是为了方便地统一以根目录为原始路径,调用node.js原生的`path.resolve` api, 来获得统一的系统绝对路径.\n\n\n\u003e P.S. 参考Angular官方文档中对webpack的一个tutorial[WEBPACK: AN INTRODUCTION](https://angular.io/docs/ts/latest/guide/webpack.html)\n\u003e 中提及的一个工具类helpers\n\n\n`tasks/config/webpack.base.config.js`\n\n\n`tasks/config/webpack.base.config.js`\n\n内容:\n```javascript\nmodule.exports = {\n  entry: {\n    main: './src/main.js'\n  },\n  resolve: {\n    extensions: ['.js']\n  },\n  plugins: []\n};\n```\n\n这里放的是公共的项目entry\n\n`tasks/config/webpack.dev.config.js`\n\n内容\n```javascript\nvar os = require('os');\nvar webpack = require('webpack');\nvar merge = require('webpack-merge');\n\nvar HtmlWebpackPlugin = require('html-webpack-plugin');\n\n\nvar baseConfig = require('./base.config');\nvar webpackBaseConfig = require('./webpack.base.config');\n\nvar pathUtil = require('../util/path-util');\n\n\nconst PROTOCOL = 'http://';\nconst HOST = '127.0.0.1';\nconst PORT = 5001;\n\nvar webpackDevConfig = merge(webpackBaseConfig, {\n  devtool: 'source-map',\n  output: {\n    path: pathUtil.root(baseConfig.dir.build),\n    publicPath: PROTOCOL + HOST + ':' + PORT,\n    filename: '[name].bundle.js',\n    sourceMapFilename: '[name].bundle.js.map',\n    chunkFilename: '[id].chunk.js'\n  },\n  devServer: {\n    host: HOST,\n    port: PORT\n  },\n  plugins: [\n    new webpack.DefinePlugin({\n      'process.env': {\n        NODE_ENV: '\"development\"'\n      }\n    }),\n    new webpack.optimize.CommonsChunkPlugin({\n      name: 'vendor',\n      minChunks: function (module) {\n        return (\n          module.resource \u0026\u0026\n          /\\.js$/.test(module.resource) \u0026\u0026\n          module.resource.indexOf(\n            pathUtil.root('node_modules')\n          ) === 0\n        );\n      }\n    }),\n    new HtmlWebpackPlugin({\n      template: 'src/index.html',\n      favicon: 'src/favicon.ico'\n    }),\n    new webpack.HotModuleReplacementPlugin(),\n    new webpack.NoEmitOnErrorsPlugin()\n  ]\n});\n\nmodule.exports = webpackDevConfig;\n```\n\n说明:\n这里开始配置文件相对上一个章节的样例,更变的非常多.\n\n由于是本地开发时环境配置,所以多出的`devServer`选项指的是`webpack-dev-server`运行时的端口配置,本配置文件默认是5001端口.\n\n在`plugins`方面:  `webpack.DefinePlugin`声明了一个前端构建时的环境变量,\n按照此代码中的说明\n可以在前端文件中使用表达式`process.env.NODE_ENV`,在构建过程中会被转译为对应的`development`字符串,并且在浏览器中不能通过 手敲'process.env.NODE_ENV' 取值. \n\n\u003e 参考Webpack Definition Plugin[官方文档](https://webpack.js.org/plugins/define-plugin/) \n\n\n名为`vendor`的`webpack.optimize.CommonsChunkPlugin`的作用,则是将`angularjs`,`@uirouter/angularjs`这种第三方的类库与业务应用的代码分割成不同的文件.\n\n\n\u003e 思考: 这样分割的好处是什么?\n\n\n\n\n`tasks/config/webpack.prod.config.js`\n\n内容:\n```javascript\nvar webpack = require('webpack');\nvar merge = require('webpack-merge');\n\nvar HtmlWebpackPlugin = require('html-webpack-plugin');\nvar ExtractTextPlugin = require('extract-text-webpack-plugin');\nvar OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');\nvar CopyWebpackPlugin = require('copy-webpack-plugin');\n\nvar baseConfig = require('./base.config');\nvar webpackBaseConfig = require('./webpack.base.config');\n\nvar pathUtil = require('../util/path-util');\n\n\nvar webpackProdConfig = merge(webpackBaseConfig, {\n\n  devtool: 'source-map',\n  output: {\n    path: pathUtil.root(baseConfig.dir.dist),\n    filename: '[name].[chunkhash].js',\n    chunkFilename: '[id].[chunkhash].js'\n  },\n  plugins: [\n    new webpack.DefinePlugin({\n      'process.env': {\n        NODE_ENV: '\"production\"'\n      }\n    }),\n    new webpack.optimize.CommonsChunkPlugin({\n      name: 'vendor',\n      minChunks: function (module) {\n        return (\n          module.resource \u0026\u0026\n          /\\.js$/.test(module.resource) \u0026\u0026\n          module.resource.indexOf(\n            pathUtil.root('node_modules')\n          ) === 0\n        );\n      }\n    }),\n    new webpack.optimize.UglifyJsPlugin({\n      compress: {\n        warnings: false\n      },\n      sourceMap: true\n    }),\n    new webpack.LoaderOptionsPlugin({\n      minimize: true\n    }),\n    new OptimizeCssAssetsPlugin({\n      cssProcessorOptions: {\n        safe: true,\n        discardComments: {\n          removeAll: true\n        }\n      },\n      canPrint: false\n    }),\n    new ExtractTextPlugin({\n      filename: '[name].[chunkhash].css'\n    }),\n    new HtmlWebpackPlugin({\n      template: './' + baseConfig.dir.src + '/index.html',\n      favicon: './' + baseConfig.dir.src + '/favicon.ico',\n      inject: true,\n      minify: {\n        removeComments: true,\n        collapseWhitespace: true,\n        removeAttributeQuotes: false\n      },\n      chunksSortMode: 'dependency'\n    })\n  ]\n});\n\nmodule.exports = webpackProdConfig;\n```\n\n说明:\n\n对于生产环境的配置,则主要是对构建出的文件做一连串的上线前准备,\n包括但不限于:\n\n- 最小化静态资源文件体积\n- 将文件hash值加入到文件命名中\n- .....\n\n\u003e 思考: 这里能看到一些与dev.config相同的plugins 配置,为什么会这样?\n\n\n`tasks/clean.js`\n\n内容:\n```javascript\nvar gulp = require('gulp');\nvar rimraf = require('gulp-rimraf');\nvar sequence = require('gulp-sequence');\nvar gutil = require('gulp-util');\n\nvar baseConfig = require('./config/base.config');\n\ngulp.task('clean', sequence(['clean:build', 'clean:dist']));\n\n\ngulp.task('clean:build', function () {\n  gutil.log('Deleting build folder');\n  return gulp.src(baseConfig.dir.build)\n    .pipe(rimraf());\n});\n\n\ngulp.task('clean:dist', function () {\n  gutil.log('Deleting dist folder');\n  return gulp.src(baseConfig.dir.dist)\n    .pipe(rimraf());\n});\n```\n\n说明:\n\n`clean:dist`,`clean:build`,`clean` 作用都是删除对应的文件夹.\n\n介绍一下这里用到的`gulp`插件:\n\n- `gulp-rimraf` 用于删除对应文件夹\n- `gulp-sequence` gulp 任务流的顺序控制\n- `gulp-util`常用来输出调试信息\n\n\n\n\n\n`tasks/build.js`\n\n内容:\n```javascript\nvar gulp = require('gulp');\nvar gutil = require('gulp-util');\nvar sequence = require('gulp-sequence');\n\nvar webpack = require('webpack');\n\n\nvar webpackProdConfig = require('./config/webpack.prod.config');\n\ngulp.task('webpack', function (done) {\n  gutil.log('Webpack building.');\n  webpack(webpackProdConfig, function (error, stats) {\n    if (error) {\n      throw new gutil.PluginError('webpack', error);\n    }\n    gutil.log(stats.toString(webpackProdConfig.stats));\n    gutil.log('Webpack build done');\n    done();\n  });\n});\n\ngulp.task('build', sequence(['clean'], ['webpack']));\n```\n\n说明:\n\nbuild的任务流代码比较容易懂,意思就是先执行预先定义好的`clean`task.\n\n接着执行`webpack`task: 根据`webpack.prod.config.js`构建出生产环境的资源文件\n\n\n`tasks/serve.js`\n\n内容:\n\n```javascript\nvar gulp = require('gulp');\nvar gutil = require('gulp-util');\nvar sequence = require('gulp-sequence');\n\nvar webpack = require('webpack');\n\nvar WebpackDevServer = require('webpack-dev-server');\nvar addDevServerEntrypoints = require('webpack-dev-server/lib/util/addDevServerEntrypoints');\n\nvar webpackDevConfig = require('./config/webpack.dev.config');\n\n\ngulp.task('serve', function () {\n  gutil.log('Webpack building.');\n  gutil.log(webpackDevConfig.devServer.host + ':' + webpackDevConfig.devServer.port);\n  addDevServerEntrypoints(webpackDevConfig, webpackDevConfig.devServer);\n  var compilerConfig = webpack(webpackDevConfig);\n  new WebpackDevServer(compilerConfig, webpackDevConfig.devServer)\n    .listen(webpackDevConfig.devServer.port, webpackDevConfig.devServer.host, function (error) {\n      if (error) {\n        throw new gutil.PluginError('webpack', error);\n      }\n    });\n});\n```\n\n说明:\n\n`serve`这个task,表示通过读取开发时webpack配置`webapck.dev.config`, 启动一个`webapck-dev-server`的实例.\n\n\n### 总结\n在这一章节,我们大概了解到了:\n\n- 使用gulp任务流控制webpack构建\n- 拆分不同环境的webpack构建配置\n\n### 思考\n- 那么CSS也能通过webpack构建吗, CSS的哪种模块导入导出语法能够被`webpack`或其`loaders`正确识别?\n- 那么项目的静态媒体资源,比如图标,字体,固定的logo图片等应该如何配置,也需要使用\nrequire进行管理吗?使用webpack管理媒体资源的主流工作方式是怎样的?\n- AngularJS 里面的directive,component,service,values,constant,service,factory等其他功能,应该如何以CommonJS的形式编写?\n- ......\n\n### 参考文章\n\n[WebpackMerge是如何Merge Configuration的?](https://github.com/survivejs/webpack-merge)\n\n\n\n\n## Webpack-Gulp-AngularJS-Boilerplate\n\n通过上一节样例的解析,我们了解到了一个基本的`webpack`+`angularjs`+`gulp`结合的,稍有眉目的工程代码.\n\n但是要应用到实际项目中,还有很多明显的问题需要解决,包括但不限于:\n\n通用部分:\n- CSS,Fonts等资源文件如何进行打包?\n- Server代码不是Node.js应用,如何与其他类型的后端项目结合在一起吗?\n\nAngularJS部分:\n- 如何管理angularjs的视图部分的html文件?\n- 如何拆分angularjs的模块\n\n\n这一章的样例代码,在上一章的基础上,添加了以下功能:\n\n- 利用webpack的`ng-cache-loader`解析angularjs `html`视图文件\n- 利用webpack的`style-loader`,`css-loader`提供css文件构建样例\n- 提供`angularjs`项目功能模块化的一种实现思路与实现\n- 提供与`koa`,`express`,`springboot`等常见后台工程的整合方案\n\n- 添加`bootstrap`的css样式 (有需要可自行替换)\n- 添加`angular-ui-bootstrap`作为基本的angular组件框架 (有需要可自行替换)\n- 添加了一个可选的`webpack-dev-server-proxy`方便开发环境与单独分离的后台进行整合 (详情请见下文代码说明)\n\n\n为解决实际项目中遇到的问题做了其中一种实现,提供了一种较普遍的思路.\n\n### 安装项目依赖\n\n```bash\ncd webpack-gulp-angularjs-boilerplate\nnpm install\n```\n\n\n### 运行项目\n```bash\nnpm run dev\n```\n\n### 与其他后台项目整合\n\n与其他后台项目整合,前提是对后台项目的代码结构和运行过程有一定的了解,\n\n本项目只从以下几个 ~~我只懂的~~ 技术栈展开描述:\n\n- Node.js - Express\n- Node.js - KOA2\n- Java - SpringBoot(Maven)\n\n我们先回顾一下`task/config/base.config.js`:\n\n还记得`base.config.js`文件存在的意义吗?\n\n\u003e P.S. 在上一章有提及到这一句:  \n\u003e 因此我把改动频率较大,只需开发者关心且修改频率可能很大的部分抽取到`base.config.js`里面.\n\n```js\nmodule.exports = {\n  dir: {\n    src: 'src',\n    build: 'build',\n\n    // default: public\n    // backend-springboot : ../backend-springboot/src/main/resources/public\n    // backend-koa: ../backend-koa/public\n    // backend-express:  ../backend-express/public\n    dist: 'public'\n  }\n};\n```\n\n当前我们有三个后台类型的项目,没有任何功能,只是单纯的运行起来.\n\n分别处于项目根目录下的`backend-express`,`backend-koa`,`backend-springboot`里面.\n\n只要把`base.config.js`中的`dist`一值修改成 注释中的`backend-express`,`backend-koa`,`backend-springboot`其中一个的值.\n\n在通过运行`npm run build`就能把生成的资源文件自动打包到对应项目的默认静态资源文件夹.\n\n对于那些前后端项目相结合的项目,基本上生产环境的构建都可以通过这类指定输出目录/文件夹复制 的功能去实现.\n\n### 代码说明\n\n这一轮主为了实现上面提及的新功能, 添加的代码大概如下:\n\n- 添加`bootstrap`的css样式 (有需要可自行替换)\n- 利用webpack的`ng-cache-loader`解析angularjs `html`视图文件\n- 利用webpack的`style-loader`,`css-loader`提供css文件构建样例\n- 提供`angularjs`项目功能模块化的一种实现思路与实现\n- 提供与`koa`,`express`,`springboot`等常见后台工程的整合方案\n\n- 添加`angular-ui-bootstrap`作为基本的angular组件框架 (有需要可自行替换)\n- 添加了一个可选的`webpack-dev-server-proxy`方便开发环境与单独分离的后台进行整合 (详情请见下文代码说明)\n\n\n#### 依赖文件更变\n因为使用了`bootstrap.css`和`angular-ui-router`,所以可以看到`package.json`里面多了这两个依赖.\n\n##### bootstrap.css\n\n在引入`bootstrap.css`方面, 修改的文件涉及下面几个方面:\n- 全局的 `styles.css` 文件入口\n- `webpack.base.config`关于bootstrap.css中定义的 `Glyphicons` 相关icon-font 的loaders\n\n###### 全局的styles.css入口\n1. 在src文件夹下, 新增了一个 `styles.css`\n这个文件,主要是用来做样式文件的一个entry.\n\nQ: 什么时候需要修改这个`styles.css`?\n\nA: 修改style.css 入口文件一般的情景有:\n- 新增了一些第三方(vendor)类库的, 样式文件位于 `node_modules` 文件夹下的css文件.\n- 自定义的一些其他可拆分的css/less/sass 文件\n\n如此样例所示: 只需要在里面使用`@import` 语法进行引入即可\n```\n@import \"~bootstrap/dist/css/bootstrap.css\";\n```\n\n###### webpack.config 新增 entry\n同时也能看到`webpack.base.config,js`为了适应修改,新增了一个entry\n\n\n```\nentry: {\n  main: './src/main.js'\n}\n```\n\n变为\n\n```\nentry: {\n  main: './src/main.js',\n  styles: './src/styles.css'\n}\n```\n###### webpack.config 新增 loaders\n\n为了适应一些静态资源文件(偏样式方面)的加载, 新增了一系列loaders.\n\n可以看到在`webpack.base.config.js`的`module`里的`rules`, 新增了如下的加载规则和对应的loaders:\n\n```\n{\n  test: /\\.css$/,\n  exclude: pathUtil.root(baseConfig.dir.src, 'app'),\n  loader: ExtractTextPlugin.extract({\n    use: ['css-loader'],\n    fallback: ['style-loader']\n  })\n},\n{\n  test: /\\.css$/,\n  include: pathUtil.root(baseConfig.dir.src, 'app'),\n  loader: ExtractTextPlugin.extract({\n    use: ['css-loader'],\n    fallback: ['style-loader']\n  })\n},\n{\n  test: /\\.(png|jpe?g|gif|ico)$/,\n  loader: 'url-loader',\n  options: {\n    limit: 10000,\n    useRelativePath: true,\n    publicPath: './',\n    name: '[name].[ext]'\n  }\n},\n{\n  test: /\\.(woff|woff2|svg|ttf|eot)$/,\n  loader: 'file-loader',\n  options: {\n    limit: 10000,\n    useRelativePath: false,\n    publicPath: './',\n    name: '[name].[ext]'\n  }\n}\n```\n\n前两个规则(rules), 表示分别对应于位于`node_modules`和位于`src/app`文件夹下的所有目录的所有以`.css`结尾的文件.\n通过`css-loader`进行加载.\n\n\u003e 思考: 这样分开有什么好的意义吗?\n\n第三个规则, 表示在所有entry解析到的文件中, 根据不同的资源文件的后缀, 使用不同的loader.\n\n并且在需要的时候, 可以把他们释放到指定的相对的路径, 亦或是当这个资源文件过小的时候, 以base64编码形式融合在打包好的css/js文件中, 而非独立文件.\n\n第四个规则, 同第三个规则, 但是是用`file-loader`对字体相关的文件进行处理.\n\n这里的第三个和第四个规则, 在加载`bootstrap.css`的过程中, 生效, 并做了如下处理:\n\n在完整的`bootstrap.css`中,有如下一段引入`icon-font`的代码:\n```\n....\n@font-face {\n  font-family: 'Glyphicons Halflings';\n\n  src: url('../fonts/glyphicons-halflings-regular.eot');\n  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');\n}\n....\n```\n在原来位于`node_modules`文件夹下的文件结构时, 此段代码表示他会去读取`'../fonts/glyphicons-halflings-regular.eot'`.\n\n我们来看一下这个`bootstrap/dist`下的文件结构:\n```\n├───css\n│       bootstrap-theme.css\n│       bootstrap-theme.css.map\n│       bootstrap-theme.min.css\n│       bootstrap-theme.min.css.map\n│       bootstrap.css\n│       bootstrap.css.map\n│       bootstrap.min.css\n│       bootstrap.min.css.map\n│\n├───fonts\n│       glyphicons-halflings-regular.eot\n│       glyphicons-halflings-regular.svg\n│       glyphicons-halflings-regular.ttf\n│       glyphicons-halflings-regular.woff\n│       glyphicons-halflings-regular.woff2\n│\n└───js\n        bootstrap.js\n        bootstrap.min.js\n        npm.js\n```\n\n因为上面第四个`file-loader`的配置,\nwebpack在进行构建解析的时候, 会把所需要的这些字体文件后缀的文件, 搬到最终 `dist` 文件夹下的根路径.\n\n所以在webpack构建后的路径,我们再来找一下这个`font-face`字段:\n\n```\n@font-face {\n  font-family: Glyphicons Halflings;\n  src: url(glyphicons-halflings-regular.eot);\n  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\")\n}\n```\n\n\n#### webpack 与 angularjs 视图模板\n\n在上面提及 webpack module rules 的时候, 我们已经看到了不止新增了4条rule.\n\n还有一条 `ng-cache-loader` 的loader.\n\n这个配置的意思是, 对于 非`src`目录下的`index.html`, 其他在项目中被entry 引用的`html`文件, 都会使用\n`ng-cache-loader`进行加载, 直接将他变成一个 `angularjs`中的 `view template`.\n\n\n具体用法, 可以参见上一个项目的 `src/app/routes.js` 的更变:\n\n在上一个项目中, `src/app/routes.js` 大概是这样的:\n\n在 `template` 字段直接进行模板 html内容的声明. \n```javascript\nmodule.exports = function ($stateProvider) {\n  $stateProvider\n    .state({\n      name: 'default',\n      url: '',\n      template: ' \u003ch3\u003eHello ITA\u003c/h3\u003e'\n    })\n    .state({\n      name: 'home',\n      url: '/',\n      template: ' \u003ch3\u003eHello ITA\u003c/h3\u003e'\n    })\n    .state({\n      name: 'about',\n      url: '/about',\n      template: '\u003ch3\u003eAbout: This is an ITA Application\u003c/h3\u003e'\n    });\n};\n```\n\n使用了`ng-cache-loader`之后, 我们可以通过如下几种方式来引用 模板html文件.\n\n举一种使用方式 :\n\n```\nmodule.exports = function ($stateProvider) {\n  $stateProvider\n    .state({\n      name: 'login',\n      url: '/login',\n      template: require('../layouts/login/login.html')\n    })\n    .state({\n      name: 'register',\n      url: '/register',\n      template: require('../layouts/register/register.html')\n    })\n};\n```\n\n\n#### Webpack的开发时代理中间件\n\n在过往的时候, 在大部分前后端分离开发的项目, 有一个比较蛋疼的地方就是: \n每一次前端资源文件更新 都需要将他转移到 后端文件夹对应的目录.\n\n`webpack-dev-server`的proxy中间件, 则方便的实现了这些功能(相对于各种实现代理的工具,最重要的是他能够在进行代理的时候,支持websocket).\n\n在刚才预先提供的后台简单项目`backend-springboot`里面, 提供了一个api, 其url为\n\n[http://127.0.0.1:8080/api/v1/validate-json](http://127.0.0.1:8080/api/v1/validate-json)\n\n而现在这个`webpack-gulp-angularjs-boilerplate`, 前端开发时, 默认是监听 5001 端口.\n\n通过在`webpack.dev.config.js`的`devServer`中添加 proxy相关配置,\n下面代码表示, 监听开发时端口(5001) 的所有发送到 `/api/*`的http请求, 都转发到\n`127.0.0.1:8080`(你的后端服务器监听端口)\n\n那么我们可以在前端开发时,通过访问 [http://127.0.0.1:5001/api/v1/validate-json](http://127.0.0.1:5001/api/v1/validate-json)\n来实现代理转发的功能. \n\n\n```\nproxy: {\n  '/api': {\n    target: 'http://127.0.0.1:8080/', \n    secure: false,\n    ws: true\n  }\n}\n```\n\n\n### 总结\n\n此项目可以用作Simple Project的一个前端方面的手脚架, 他遵循并通过现有的工具实现了一些前端工程方面常见的较佳实践.\n\n但是前端工程化依然发展的很快, 此项目仅仅以`angularjs + commonjs语法`作为一个例子.\n可以说为日后将要遇到的`Angular`,`Vue`,`React`等更先进的前端框架, 亦或是更高级的构建工具, 提供了一个基本的开发思维与工具升级实践.\n\n希望在了解这个进化过程的基础上, 在遇到新的前端项目时候, 能够快速了解其构件流程, 举一反三, 快速上手.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faquariuslt%2Fwebpack-revolution","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faquariuslt%2Fwebpack-revolution","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faquariuslt%2Fwebpack-revolution/lists"}