├── chapter3
├── webpack-advanced
│ ├── src
│ │ ├── hotmodule.js
│ │ ├── css
│ │ │ ├── index.css
│ │ │ └── b.css
│ │ ├── constant.js
│ │ ├── scss
│ │ │ └── index.scss
│ │ ├── math.js
│ │ ├── less
│ │ │ └── index.less
│ │ ├── images
│ │ │ ├── bg.jpg
│ │ │ └── itcast_logo.png
│ │ ├── other.js
│ │ ├── a.js
│ │ ├── api
│ │ │ └── http.js
│ │ ├── other.html
│ │ ├── index.html
│ │ ├── index.js
│ │ └── main.js
│ ├── assets
│ │ └── logo.png
│ ├── .babelrc
│ ├── webpack.custom.config.js
│ ├── server.js
│ ├── build
│ │ ├── webpack.prod.js
│ │ ├── webpack.dev.js
│ │ └── webpack.base.js
│ └── package.json
└── server
│ ├── app.js
│ ├── package.json
│ └── package-lock.json
├── chapter4
├── webpack-optimize
│ ├── src
│ │ ├── hotmodule.js
│ │ ├── css
│ │ │ ├── index.css
│ │ │ └── b.css
│ │ ├── constant.js
│ │ ├── scss
│ │ │ └── index.scss
│ │ ├── math.js
│ │ ├── less
│ │ │ └── index.less
│ │ ├── images
│ │ │ ├── bg.jpg
│ │ │ └── itcast_logo.png
│ │ ├── other.js
│ │ ├── a.js
│ │ ├── api
│ │ │ └── http.js
│ │ ├── other.html
│ │ ├── index.html
│ │ ├── index.js
│ │ └── main.js
│ ├── assets
│ │ └── logo.png
│ ├── .babelrc
│ ├── webpack.custom.config.js
│ ├── server.js
│ ├── build
│ │ ├── webpack.prod.js
│ │ ├── webpack.dev.js
│ │ └── webpack.base.js
│ └── package.json
├── webpack-optimize-js
│ ├── src
│ │ ├── a.js
│ │ ├── other.js
│ │ ├── main.react.js
│ │ ├── index.html
│ │ └── main.js
│ ├── postcss.config.js
│ ├── assets
│ │ └── logo.png
│ ├── .babelrc
│ ├── build
│ │ ├── webpack.react.js
│ │ ├── webpack.vue.js
│ │ ├── webpack.prod.js
│ │ ├── webpack.dev.js
│ │ └── webpack.base.js
│ ├── package.json
│ └── stats.json
└── webpack-optimize-css
│ ├── src
│ ├── css
│ │ ├── index.css
│ │ └── b.css
│ ├── scss
│ │ └── index.scss
│ ├── images
│ │ ├── bg.jpg
│ │ └── itcast_logo.png
│ ├── less
│ │ └── index.less
│ ├── main.js
│ └── index.html
│ ├── postcss.config.js
│ ├── assets
│ └── logo.png
│ ├── .babelrc
│ ├── build
│ ├── webpack.prod.js
│ ├── webpack.dev.js
│ └── webpack.base.js
│ └── package.json
├── chapter2
└── webpack-basic
│ ├── src
│ ├── css
│ │ ├── index.css
│ │ └── b.css
│ ├── scss
│ │ └── index.scss
│ ├── less
│ │ └── index.less
│ ├── images
│ │ └── bg.jpg
│ ├── a.js
│ ├── index.html
│ └── main.js
│ ├── assets
│ └── logo.png
│ ├── .babelrc
│ ├── webpack.custom.config.js
│ ├── server.js
│ ├── package.json
│ └── webpack.config.js
├── chapter5
├── webpack-demo
│ ├── src
│ │ ├── index.css
│ │ ├── message.js
│ │ ├── index.js
│ │ ├── news.js
│ │ └── index.html
│ ├── loaders
│ │ ├── loader3.js
│ │ ├── loader2.js
│ │ └── loader1.js
│ ├── package.json
│ ├── plugins
│ │ ├── HelloWorldPlugin.js
│ │ └── HTMLPlugin.js
│ └── webpack.config.js
└── itheima-pack
│ ├── bin
│ └── itheima-pack.js
│ ├── package.json
│ ├── template
│ └── output.ejs
│ ├── test
│ └── tapable-hellworld.js
│ ├── lib
│ └── Compiler.js
│ └── package-lock.json
├── assets
├── 跨域.png
├── 解决跨域.png
├── webpack.png
├── 1558771916946.png
├── 1558772012664.png
├── 1559811338075.png
├── 1561174288710.png
├── 1561895540321.png
├── main.bundle.js.png
├── other.bundle.js.png
└── HappyPack_Workflow.png
├── chapter1
└── webpack-basic
│ ├── src
│ ├── a.js
│ └── main.js
│ ├── webpack.custom.config.js
│ ├── index.html
│ ├── webpack.config.js
│ └── package.json
├── .gitignore
└── README.md
/chapter3/webpack-advanced/src/hotmodule.js:
--------------------------------------------------------------------------------
1 | export default '好热!真的热!'
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/hotmodule.js:
--------------------------------------------------------------------------------
1 | export default '好热!真的热!'
--------------------------------------------------------------------------------
/chapter2/webpack-basic/src/css/index.css:
--------------------------------------------------------------------------------
1 | li {
2 | line-height: 50px;
3 | }
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/css/index.css:
--------------------------------------------------------------------------------
1 | li {
2 | line-height: 50px;
3 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/src/a.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: '我是a'
3 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/css/index.css:
--------------------------------------------------------------------------------
1 | li {
2 | line-height: 50px;
3 | }
--------------------------------------------------------------------------------
/chapter5/webpack-demo/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: red;
3 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/src/css/index.css:
--------------------------------------------------------------------------------
1 | li {
2 | line-height: 50px;
3 | }
--------------------------------------------------------------------------------
/chapter5/webpack-demo/src/message.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | content: '今天要下雨了!!!'
3 | }
--------------------------------------------------------------------------------
/assets/跨域.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/assets/跨域.png
--------------------------------------------------------------------------------
/chapter2/webpack-basic/src/css/b.css:
--------------------------------------------------------------------------------
1 | li:last-of-type {
2 | background-color: pink;
3 | }
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/css/b.css:
--------------------------------------------------------------------------------
1 | li:last-of-type {
2 | background-color: pink;
3 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/css/b.css:
--------------------------------------------------------------------------------
1 | li:last-of-type {
2 | background-color: pink;
3 | }
--------------------------------------------------------------------------------
/assets/解决跨域.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/assets/解决跨域.png
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/src/css/b.css:
--------------------------------------------------------------------------------
1 | li:last-of-type {
2 | background-color: pink;
3 | }
--------------------------------------------------------------------------------
/assets/webpack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/assets/webpack.png
--------------------------------------------------------------------------------
/chapter2/webpack-basic/src/scss/index.scss:
--------------------------------------------------------------------------------
1 | ul {
2 | li {
3 | font-family: "consolas"
4 | }
5 | }
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/constant.js:
--------------------------------------------------------------------------------
1 | export let a = 10
2 | export let b = 20
3 | export let c = 30
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/constant.js:
--------------------------------------------------------------------------------
1 | export let a = 10
2 | export let b = 20
3 | export let c = 30
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/scss/index.scss:
--------------------------------------------------------------------------------
1 | ul {
2 | li {
3 | font-family: "consolas"
4 | }
5 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/scss/index.scss:
--------------------------------------------------------------------------------
1 | ul {
2 | li {
3 | font-family: "consolas"
4 | }
5 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('autoprefixer')]
3 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/src/scss/index.scss:
--------------------------------------------------------------------------------
1 | ul {
2 | li {
3 | font-family: "consolas"
4 | }
5 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('autoprefixer')]
3 | }
--------------------------------------------------------------------------------
/assets/1558771916946.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/assets/1558771916946.png
--------------------------------------------------------------------------------
/assets/1558772012664.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/assets/1558772012664.png
--------------------------------------------------------------------------------
/assets/1559811338075.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/assets/1559811338075.png
--------------------------------------------------------------------------------
/assets/1561174288710.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/assets/1561174288710.png
--------------------------------------------------------------------------------
/assets/1561895540321.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/assets/1561895540321.png
--------------------------------------------------------------------------------
/assets/main.bundle.js.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/assets/main.bundle.js.png
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/math.js:
--------------------------------------------------------------------------------
1 | export const add = (a, b) => a + b
2 |
3 | export const minus = (a, b) => a - b
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/math.js:
--------------------------------------------------------------------------------
1 | export const add = (a, b) => a + b
2 |
3 | export const minus = (a, b) => a - b
--------------------------------------------------------------------------------
/assets/other.bundle.js.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/assets/other.bundle.js.png
--------------------------------------------------------------------------------
/assets/HappyPack_Workflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/assets/HappyPack_Workflow.png
--------------------------------------------------------------------------------
/chapter5/webpack-demo/src/index.js:
--------------------------------------------------------------------------------
1 | let news = require('./news.js')
2 | console.log(news.content)
3 |
4 | // require('./index.css')
--------------------------------------------------------------------------------
/chapter2/webpack-basic/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/chapter2/webpack-basic/assets/logo.png
--------------------------------------------------------------------------------
/chapter2/webpack-basic/src/less/index.less:
--------------------------------------------------------------------------------
1 | ul {
2 | background-image: url(../images/bg.jpg);
3 | li {
4 | font-size: 38px;
5 | }
6 | }
--------------------------------------------------------------------------------
/chapter2/webpack-basic/src/images/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/chapter2/webpack-basic/src/images/bg.jpg
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/less/index.less:
--------------------------------------------------------------------------------
1 | ul {
2 | background-image: url(../images/bg.jpg);
3 | li {
4 | font-size: 38px;
5 | }
6 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/src/other.js:
--------------------------------------------------------------------------------
1 | import $ from 'jquery'
2 | $(function() {
3 | $('
').html('我是other').appendTo('body')
4 | })
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/less/index.less:
--------------------------------------------------------------------------------
1 | ul {
2 | background-image: url(../images/bg.jpg);
3 | li {
4 | font-size: 38px;
5 | }
6 | }
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/chapter3/webpack-advanced/assets/logo.png
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/images/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/chapter3/webpack-advanced/src/images/bg.jpg
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/chapter4/webpack-optimize/assets/logo.png
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/images/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/chapter4/webpack-optimize/src/images/bg.jpg
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/chapter4/webpack-optimize-css/assets/logo.png
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/chapter4/webpack-optimize-js/assets/logo.png
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/src/images/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/chapter4/webpack-optimize-css/src/images/bg.jpg
--------------------------------------------------------------------------------
/chapter5/webpack-demo/src/news.js:
--------------------------------------------------------------------------------
1 | let message = require('./message.js')
2 |
3 | module.exports = {
4 | content: '今天有个大新闻,爆炸消息!!!内容是:' + message.content
5 | }
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/images/itcast_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/chapter3/webpack-advanced/src/images/itcast_logo.png
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/other.js:
--------------------------------------------------------------------------------
1 | console.log('我是other.js')
2 |
3 | // import $ from 'jquery'
4 |
5 | // $('body img').css('width', '300px').css('height', '300px')
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/images/itcast_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/chapter4/webpack-optimize/src/images/itcast_logo.png
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/other.js:
--------------------------------------------------------------------------------
1 | console.log('我是other.js')
2 |
3 | // import $ from 'jquery'
4 |
5 | // $('body img').css('width', '300px').css('height', '300px')
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/src/images/itcast_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TianchengLee/webpack-tutorial/master/chapter4/webpack-optimize-css/src/images/itcast_logo.png
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/src/less/index.less:
--------------------------------------------------------------------------------
1 | ul {
2 | background-image: url(../images/bg.jpg);
3 | transform: rotate(30deg);
4 | li {
5 | font-size: 38px;
6 | }
7 | }
--------------------------------------------------------------------------------
/chapter2/webpack-basic/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/env"],
3 | "plugins": [
4 | "@babel/plugin-proposal-class-properties",
5 | "@babel/plugin-transform-runtime"
6 | ]
7 | }
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/env"],
3 | "plugins": [
4 | "@babel/plugin-proposal-class-properties",
5 | "@babel/plugin-transform-runtime"
6 | ]
7 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/env"],
3 | "plugins": [
4 | "@babel/plugin-proposal-class-properties",
5 | "@babel/plugin-transform-runtime"
6 | ]
7 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/env"],
3 | "plugins": [
4 | "@babel/plugin-proposal-class-properties",
5 | "@babel/plugin-transform-runtime"
6 | ]
7 | }
--------------------------------------------------------------------------------
/chapter1/webpack-basic/src/a.js:
--------------------------------------------------------------------------------
1 | console.log('我是a模块')
2 | // CommonJS的导出语法规范
3 | // module.exports = {
4 | // name: 'aaa'
5 | // }
6 |
7 | // ES6的导出语法规范
8 | export default {
9 | name: 'aaa'
10 | }
--------------------------------------------------------------------------------
/chapter2/webpack-basic/src/a.js:
--------------------------------------------------------------------------------
1 | console.log('我是a模块')
2 | // CommonJS的导出语法规范
3 | // module.exports = {
4 | // name: 'aaa'
5 | // }
6 |
7 | // ES6的导出语法规范
8 | export default {
9 | name: 'aaa'
10 | }
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/a.js:
--------------------------------------------------------------------------------
1 | console.log('我是a模块')
2 | // CommonJS的导出语法规范
3 | // module.exports = {
4 | // name: 'aaa'
5 | // }
6 |
7 | // ES6的导出语法规范
8 | export default {
9 | name: 'aaa'
10 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/a.js:
--------------------------------------------------------------------------------
1 | console.log('我是a模块')
2 | // CommonJS的导出语法规范
3 | // module.exports = {
4 | // name: 'aaa'
5 | // }
6 |
7 | // ES6的导出语法规范
8 | export default {
9 | name: 'aaa'
10 | }
--------------------------------------------------------------------------------
/chapter1/webpack-basic/src/main.js:
--------------------------------------------------------------------------------
1 | // CommonJS规范 在浏览器中不支持
2 | // let a = require('./a.js')
3 |
4 | // ES6的导入导出语法规范
5 | import a from './a.js'
6 | console.log(a)
7 | console.log('黑马程序员真牛逼!')
8 | console.log('黑马程序员真牛逼! 是的牛逼!!!')
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/src/main.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 |
4 | let reactNode = React.createElement('h1', null, '我很大!!!')
5 | ReactDOM.render(reactNode, document.getElementById('app'))
--------------------------------------------------------------------------------
/chapter5/webpack-demo/loaders/loader3.js:
--------------------------------------------------------------------------------
1 | // 其实loader 就是一个函数
2 | // 使用loader1 将js文件中所有的今天 替换成 明天
3 | module.exports = function(source) {
4 | console.log('我是loader3')
5 | // loader处理完后需要把处理的结果返回
6 | return source.replace(/今天/g, '昨天')
7 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | /dist/
4 | dist/
5 | npm-debug.log*
6 | yarn-debug.log*
7 | yarn-error.log*
8 |
9 | # Editor directories and files
10 | .idea
11 | .vscode
12 | *.suo
13 | *.ntvs*
14 | *.njsproj
15 | *.sln
16 |
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/env"],
3 | "plugins": [
4 | "@babel/plugin-proposal-class-properties",
5 | "@babel/plugin-transform-runtime",
6 | "@babel/plugin-syntax-dynamic-import"
7 | ]
8 | }
--------------------------------------------------------------------------------
/chapter5/webpack-demo/loaders/loader2.js:
--------------------------------------------------------------------------------
1 | // 其实loader 就是一个函数
2 | // 使用loader1 将js文件中所有的今天 替换成 明天
3 | module.exports = function(source) {
4 | console.log('我是loader2')
5 | // loader处理完后需要把处理的结果返回
6 | return source.replace(/今天/g, '我是loader2昨天')
7 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/src/main.js:
--------------------------------------------------------------------------------
1 | // 引入css
2 | import './css/index.css'
3 | import './css/b.css'
4 |
5 | // 引入less
6 | import './less/index.less'
7 | // 引入sass
8 | import './scss/index.scss'
9 |
10 | // 引入bootstrap的css文件
11 | // import 'bootstrap/dist/css/bootstrap.css'
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/api/http.js:
--------------------------------------------------------------------------------
1 | let host = 'http://192.168.1.22:9999'
2 | if (!IS_DEV) {
3 | host = 'http://www.itheima.com'
4 | }
5 |
6 | let url = host + '/api/v1/getUserInfo'
7 |
8 | import axios from 'axios'
9 |
10 | export const getUserInfo = () => axios.get(url)
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/api/http.js:
--------------------------------------------------------------------------------
1 | let host = 'http://192.168.1.22:9999'
2 | if (!IS_DEV) {
3 | host = 'http://www.itheima.com'
4 | }
5 |
6 | let url = host + '/api/v1/getUserInfo'
7 |
8 | import axios from 'axios'
9 |
10 | export const getUserInfo = () => axios.get(url)
--------------------------------------------------------------------------------
/chapter5/itheima-pack/bin/itheima-pack.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const path = require('path')
4 | // 1. 读取需要打包项目的配置文件
5 | let config = require(path.resolve('webpack.config.js'))
6 | // console.log(config)
7 |
8 | // 2. 通过面向对象的方式来进行项目推进
9 | const Compiler = require('../lib/Compiler')
10 | new Compiler(config).start()
--------------------------------------------------------------------------------
/chapter3/server/app.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const app = express()
3 | // const cors = require('cors')
4 | // app.use(cors())
5 | app.get('/getUserInfo', (req, res) => {
6 | res.send({
7 | name: '黑马儿',
8 | age: 13
9 | })
10 | });
11 |
12 | app.listen(9999, () => {
13 | console.log('http://localhost:9999');
14 | });
--------------------------------------------------------------------------------
/chapter5/webpack-demo/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 | 我是index.html
11 |
12 |
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/other.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 | 我是other.html嘿嘿嘿
11 |
12 |
13 |
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/other.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 | 我是other.html嘿嘿嘿
11 |
12 |
13 |
--------------------------------------------------------------------------------
/chapter3/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "cors": "^2.8.5",
14 | "express": "^4.17.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/chapter5/webpack-demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-demo",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "scripts": {
7 | "build": "webpack"
8 | },
9 | "devDependencies": {
10 | "webpack": "^4.33.0",
11 | "webpack-cli": "^3.3.3"
12 | },
13 | "dependencies": {
14 | "cheerio": "^1.0.0-rc.3",
15 | "loader-utils": "^1.2.3"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/chapter1/webpack-basic/webpack.custom.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | // webpack的配置文件遵循着CommonJS规范
4 | module.exports = {
5 | entry: './src/main.js',
6 | output: {
7 | // path.resolve() : 解析当前相对路径的绝对路径
8 | // path: path.resolve('./dist/'),
9 | // path: path.resolve(__dirname, './dist/'),
10 | path: path.join(__dirname, './dist/'),
11 | filename: 'custombundle.js'
12 | },
13 | mode: 'production'
14 | }
--------------------------------------------------------------------------------
/chapter2/webpack-basic/webpack.custom.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | // webpack的配置文件遵循着CommonJS规范
4 | module.exports = {
5 | entry: './src/main.js',
6 | output: {
7 | // path.resolve() : 解析当前相对路径的绝对路径
8 | // path: path.resolve('./dist/'),
9 | // path: path.resolve(__dirname, './dist/'),
10 | path: path.join(__dirname, './dist/'),
11 | filename: 'custombundle.js'
12 | },
13 | mode: 'production'
14 | }
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/webpack.custom.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | // webpack的配置文件遵循着CommonJS规范
4 | module.exports = {
5 | entry: './src/main.js',
6 | output: {
7 | // path.resolve() : 解析当前相对路径的绝对路径
8 | // path: path.resolve('./dist/'),
9 | // path: path.resolve(__dirname, './dist/'),
10 | path: path.join(__dirname, './dist/'),
11 | filename: 'custombundle.js'
12 | },
13 | mode: 'production'
14 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/webpack.custom.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | // webpack的配置文件遵循着CommonJS规范
4 | module.exports = {
5 | entry: './src/main.js',
6 | output: {
7 | // path.resolve() : 解析当前相对路径的绝对路径
8 | // path: path.resolve('./dist/'),
9 | // path: path.resolve(__dirname, './dist/'),
10 | path: path.join(__dirname, './dist/'),
11 | filename: 'custombundle.js'
12 | },
13 | mode: 'production'
14 | }
--------------------------------------------------------------------------------
/chapter1/webpack-basic/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/chapter2/webpack-basic/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const webpack = require('webpack');
3 | const webpackDevMiddleware = require('webpack-dev-middleware');
4 | const config = require('./webpack.config.js');
5 |
6 | const app = express();
7 | const compiler = webpack(config);
8 |
9 | app.use(webpackDevMiddleware(compiler, {
10 | publicPath: '/'
11 | }));
12 |
13 | app.listen(3000, function () {
14 | console.log('http://localhost:3000');
15 | });
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const webpack = require('webpack');
3 | const webpackDevMiddleware = require('webpack-dev-middleware');
4 | const config = require('./webpack.config.js');
5 |
6 | const app = express();
7 | const compiler = webpack(config);
8 |
9 | app.use(webpackDevMiddleware(compiler, {
10 | publicPath: '/'
11 | }));
12 |
13 | app.listen(3000, function () {
14 | console.log('http://localhost:3000');
15 | });
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const webpack = require('webpack');
3 | const webpackDevMiddleware = require('webpack-dev-middleware');
4 | const config = require('./webpack.config.js');
5 |
6 | const app = express();
7 | const compiler = webpack(config);
8 |
9 | app.use(webpackDevMiddleware(compiler, {
10 | publicPath: '/'
11 | }));
12 |
13 | app.listen(3000, function () {
14 | console.log('http://localhost:3000');
15 | });
--------------------------------------------------------------------------------
/chapter1/webpack-basic/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | // webpack的配置文件遵循着CommonJS规范
4 | module.exports = {
5 | entry: './src/main.js',
6 | output: {
7 | // path.resolve() : 解析当前相对路径的绝对路径
8 | // path: path.resolve('./dist/'),
9 | // path: path.resolve(__dirname, './dist/'),
10 | path: path.join(__dirname, './dist/'),
11 | filename: 'bundle.js'
12 | },
13 | mode: 'development',
14 | // 开启监视模式, 此时执行webpack指令进行打包会监视文件变化自动打包
15 | watch: true
16 | }
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/build/webpack.prod.js:
--------------------------------------------------------------------------------
1 | const merge = require('webpack-merge')
2 | const baseConfig = require('./webpack.base.js')
3 | const webpack = require('webpack')
4 |
5 | // webpack的配置文件遵循着CommonJS规范
6 | module.exports = merge(baseConfig, {
7 | mode: 'production',
8 | devtool: 'cheap-module-source-map',
9 | plugins: [
10 | new webpack.DefinePlugin({
11 | IS_DEV: 'false',
12 | // test: '1 + 1', // DefinePlugin会解析定义的环境变量表达式, 当成JS执行
13 | // test2: '"zs"'
14 | })
15 | ]
16 | })
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/build/webpack.prod.js:
--------------------------------------------------------------------------------
1 | const merge = require('webpack-merge')
2 | const baseConfig = require('./webpack.base.js')
3 | const webpack = require('webpack')
4 |
5 | // webpack的配置文件遵循着CommonJS规范
6 | module.exports = merge(baseConfig, {
7 | mode: 'production',
8 | devtool: 'cheap-module-source-map',
9 | plugins: [
10 | new webpack.DefinePlugin({
11 | IS_DEV: 'false',
12 | // test: '1 + 1', // DefinePlugin会解析定义的环境变量表达式, 当成JS执行
13 | // test2: '"zs"'
14 | })
15 | ]
16 | })
--------------------------------------------------------------------------------
/chapter1/webpack-basic/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-basic",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "buildcustom": "webpack --config webpack.custom.config.js",
9 | "build": " ",
10 | "watch": "webpack --watch"
11 | },
12 | "keywords": [],
13 | "author": "",
14 | "license": "ISC",
15 | "devDependencies": {
16 | "webpack": "^4.30.0",
17 | "webpack-cli": "^3.3.1"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/chapter5/webpack-demo/plugins/HelloWorldPlugin.js:
--------------------------------------------------------------------------------
1 | // 1. 构造函数
2 | // 2. prototype中需要有一个apply方法
3 | module.exports = class HelloWorldPlugin {
4 | // 3. apply中有一个compiler的形参
5 | apply(compiler) {
6 | // console.log('HelloWorld')
7 | // 通过compiler对象可以注册对应的事件
8 | compiler.hooks.done.tap('HelloWorldPlugin', (stats) => {
9 | console.log('整个webpack打包结束了!!!', stats)
10 | })
11 |
12 | compiler.hooks.emit.tap('HelloWorldPlugin', (compilation) => {
13 | console.log('文件发射结束了!!!', compilation)
14 | })
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 | 去首页
13 | 去新闻
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/chapter5/itheima-pack/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "itheima-pack",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "bin": {
7 | "itheima-pack": "./bin/itheima-pack.js"
8 | },
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "keywords": [],
13 | "author": "",
14 | "license": "ISC",
15 | "dependencies": {
16 | "@babel/generator": "^7.4.4",
17 | "@babel/parser": "^7.4.5",
18 | "@babel/traverse": "^7.4.5",
19 | "ejs": "^2.6.1",
20 | "tapable": "^1.1.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/chapter5/webpack-demo/loaders/loader1.js:
--------------------------------------------------------------------------------
1 | const loaderUtils = require('loader-utils')
2 |
3 | // 其实loader 就是一个函数
4 | // 使用loader1 将js文件中所有的今天 替换成 明天
5 | module.exports = function(source) {
6 | // this.query已废弃,最新的api是使用loaderUtils.getOptions方法来获取
7 | // console.log('我是loader1', this.query)
8 | // loader处理完后需要把处理的结果返回
9 | // return source.replace(/今天/g, this.query.name)
10 | // let options = loaderUtils.getOptions(this)
11 | // console.log('我是loader1', this.query)
12 | // return source.replace(/今天/g, options.name || '明天')
13 | // return source.replace(/今天/g, '昨天')
14 | return source.replace(/今天/g, this.query.name || '昨天')
15 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/build/webpack.react.js:
--------------------------------------------------------------------------------
1 | // 这个webpack的配置文件就是用来打包vue全家桶的
2 | const path = require('path')
3 | // DllPlugin
4 | const webpack = require('webpack')
5 | module.exports = {
6 | mode: 'production',
7 | entry: {
8 | react: [
9 | 'react',
10 | 'react-dom'
11 | ]
12 | },
13 | output: {
14 | path: path.resolve(__dirname, '../dist'),
15 | filename: '[name]_dll.js',
16 | library: '[name]_dll' // 最终会在全局暴露出一个vue_dll的对象
17 | },
18 | plugins: [
19 | new webpack.DllPlugin({
20 | name: '[name]_dll',
21 | // 指定manifest.json的路径
22 | path: path.resolve(__dirname, '../dist/manifest.json')
23 | })
24 | ]
25 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/build/webpack.vue.js:
--------------------------------------------------------------------------------
1 | // 这个webpack的配置文件就是用来打包vue全家桶的
2 | const path = require('path')
3 | // DllPlugin
4 | const webpack = require('webpack')
5 | module.exports = {
6 | mode: 'production',
7 | entry: {
8 | vue: [
9 | 'vue/dist/vue.js',
10 | 'vue-router'
11 | ]
12 | },
13 | output: {
14 | path: path.resolve(__dirname, '../dist'),
15 | filename: '[name]_dll.js',
16 | library: '[name]_dll' // 最终会在全局暴露出一个vue_dll的对象
17 | },
18 | plugins: [
19 | new webpack.DllPlugin({
20 | name: '[name]_dll',
21 | // 指定manifest.json的路径
22 | path: path.resolve(__dirname, '../dist/manifest.json')
23 | })
24 | ]
25 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/build/webpack.prod.js:
--------------------------------------------------------------------------------
1 | const merge = require('webpack-merge')
2 | const baseConfig = require('./webpack.base.js')
3 | const webpack = require('webpack')
4 | const TerserJSPlugin = require('terser-webpack-plugin')
5 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
6 |
7 | // webpack的配置文件遵循着CommonJS规范
8 | module.exports = merge(baseConfig, {
9 | mode: 'production',
10 | optimization: {
11 | minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})]
12 | },
13 | devtool: 'cheap-module-source-map',
14 | plugins: [
15 | new webpack.DefinePlugin({
16 | IS_DEV: 'false',
17 | // test: '1 + 1', // DefinePlugin会解析定义的环境变量表达式, 当成JS执行
18 | // test2: '"zs"'
19 | })
20 | ]
21 | })
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/build/webpack.prod.js:
--------------------------------------------------------------------------------
1 | const merge = require('webpack-merge')
2 | const baseConfig = require('./webpack.base.js')
3 | const webpack = require('webpack')
4 | const TerserJSPlugin = require('terser-webpack-plugin')
5 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
6 |
7 | // webpack的配置文件遵循着CommonJS规范
8 | module.exports = merge(baseConfig, {
9 | mode: 'production',
10 | optimization: {
11 | minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})]
12 | },
13 | devtool: 'cheap-module-source-map',
14 | plugins: [
15 | new webpack.DefinePlugin({
16 | IS_DEV: 'false',
17 | // test: '1 + 1', // DefinePlugin会解析定义的环境变量表达式, 当成JS执行
18 | // test2: '"zs"'
19 | })
20 | ]
21 | })
--------------------------------------------------------------------------------
/chapter2/webpack-basic/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | - 1
18 | - 2
19 | - 3
20 | - 4
21 | - 5
22 | - 6
23 | - 7 helloworld
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | - 1
18 | - 2
19 | - 3
20 | - 4
21 | - 5
22 | - 6
23 | - 7 helloworld
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | - 1
18 | - 2
19 | - 3
20 | - 4
21 | - 5
22 | - 6
23 | - 7 helloworld
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | - 1
18 | - 2
19 | - 3
20 | - 4
21 | - 5
22 | - 6
23 | - 7 helloworld
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/chapter5/itheima-pack/template/output.ejs:
--------------------------------------------------------------------------------
1 | (function (modules) { // webpackBootstrap
2 | // The module cache
3 | var installedModules = {};
4 |
5 | // The require function
6 | function __webpack_require__(moduleId) {
7 |
8 | // Check if module is in cache
9 | if (installedModules[moduleId]) {
10 | return installedModules[moduleId].exports;
11 | }
12 | // Create a new module (and put it into the cache)
13 | var module = installedModules[moduleId] = {
14 | i: moduleId,
15 | l: false,
16 | exports: {}
17 | };
18 |
19 | // Execute the module function
20 | modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
21 |
22 | // Flag the module as loaded
23 | module.l = true;
24 |
25 | // Return the exports of the module
26 | return module.exports;
27 | }
28 |
29 | // Load entry module and return exports
30 | return __webpack_require__(__webpack_require__.s = "<%-entry%>");
31 | })
32 | ({
33 | <% for (let k in modules) { %>
34 | "<%-k%>":
35 | (function (module, exports, __webpack_require__) {
36 | eval(`<%-modules[k]%>`);
37 | }),
38 | <%}%>
39 | });
--------------------------------------------------------------------------------
/chapter5/webpack-demo/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const HelloWorldPlugin = require('./plugins/HelloWorldPlugin.js')
3 | const HTMLPlugin = require('./plugins/HTMLPlugin.js')
4 |
5 | module.exports = {
6 | entry: './src/index.js',
7 | output: {
8 | path: path.join(__dirname, 'dist'),
9 | filename: 'bundle.js'
10 | },
11 | plugins: [
12 | new HelloWorldPlugin(),
13 | // new HTMLPlugin({
14 | // filename: 'index.html',
15 | // template: './src/index.html'
16 | // })
17 | ],
18 | module: {
19 | rules: [
20 |
21 | // loader的加载顺序永远遵循: pre > inline > normal > post
22 | {
23 | test: /\.js$/, use: {
24 | loader: './loaders/loader1.js',
25 | options: {
26 | name: '后天2222222'
27 | }
28 | },
29 | enforce: 'pre'
30 | },
31 | // { test: /\.js$/, use: './loaders/loader2.js' },
32 | // { test: /\.js$/, use: './loaders/loader3.js', enforce: 'post' },
33 |
34 | // {
35 | // test: /\.js$/,
36 | // use: [
37 | // './loaders/loader1.js',
38 | // './loaders/loader2.js',
39 | // './loaders/loader3.js'
40 | // ]
41 | // }
42 | ]
43 | },
44 | mode: 'development'
45 | }
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/build/webpack.dev.js:
--------------------------------------------------------------------------------
1 | const merge = require('webpack-merge')
2 | const baseConfig = require('./webpack.base.js')
3 | // 引入webpack
4 | const webpack = require('webpack')
5 | // webpack的配置文件遵循着CommonJS规范
6 | module.exports = merge(baseConfig, {
7 | mode: 'development',
8 | // 开启监视模式, 此时执行webpack指令进行打包会监视文件变化自动打包
9 | // watch: true
10 | devServer: {
11 | open: true,
12 | hot: true, // 开启热更新
13 | compress: true,
14 | port: 3000,
15 | // contentBase: './src'
16 | proxy: {
17 | // /api/getUserInfo
18 | // 当前端请求 /api 地址时, 会将请求转发到
19 | // http://localhost:9999/api
20 | // 举例: 客户端现在请求的时 /api/getUserInfo
21 | // 此时会将请求转发到: http://localhost:9999/api/getUserInfo
22 | // '/api': 'http://localhost:9999',
23 | // 此时会将请求转发到: http://localhost:9999/getUserInfo
24 | // '/getUserInfo': 'http://localhost:9999'
25 | '/api': {
26 | target: 'http://localhost:9999',
27 | // 转发请求时不会携带 /api
28 | // http://localhost:9999/getUserInfo
29 | pathRewrite: {
30 | '^/api': ''
31 | }
32 | }
33 | }
34 | },
35 | devtool: 'cheap-module-eval-source-map',
36 | plugins: [
37 | new webpack.DefinePlugin({
38 | IS_DEV: 'true',
39 | // test: '1 + 1', // DefinePlugin会解析定义的环境变量表达式, 当成JS执行
40 | // test2: '"zs"'
41 | })
42 | ]
43 | })
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/build/webpack.dev.js:
--------------------------------------------------------------------------------
1 | const merge = require('webpack-merge')
2 | const baseConfig = require('./webpack.base.js')
3 | // 引入webpack
4 | const webpack = require('webpack')
5 | // webpack的配置文件遵循着CommonJS规范
6 | module.exports = merge(baseConfig, {
7 | mode: 'development',
8 | // 开启监视模式, 此时执行webpack指令进行打包会监视文件变化自动打包
9 | // watch: true
10 | devServer: {
11 | open: true,
12 | hot: true, // 开启热更新
13 | compress: true,
14 | port: 3000,
15 | // contentBase: './src'
16 | proxy: {
17 | // /api/getUserInfo
18 | // 当前端请求 /api 地址时, 会将请求转发到
19 | // http://localhost:9999/api
20 | // 举例: 客户端现在请求的时 /api/getUserInfo
21 | // 此时会将请求转发到: http://localhost:9999/api/getUserInfo
22 | // '/api': 'http://localhost:9999',
23 | // 此时会将请求转发到: http://localhost:9999/getUserInfo
24 | // '/getUserInfo': 'http://localhost:9999'
25 | '/api': {
26 | target: 'http://localhost:9999',
27 | // 转发请求时不会携带 /api
28 | // http://localhost:9999/getUserInfo
29 | pathRewrite: {
30 | '^/api': ''
31 | }
32 | }
33 | }
34 | },
35 | devtool: 'cheap-module-eval-source-map',
36 | plugins: [
37 | new webpack.DefinePlugin({
38 | IS_DEV: 'true',
39 | // test: '1 + 1', // DefinePlugin会解析定义的环境变量表达式, 当成JS执行
40 | // test2: '"zs"'
41 | })
42 | ]
43 | })
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/build/webpack.dev.js:
--------------------------------------------------------------------------------
1 | const merge = require('webpack-merge')
2 | const baseConfig = require('./webpack.base.js')
3 | // 引入webpack
4 | const webpack = require('webpack')
5 | // webpack的配置文件遵循着CommonJS规范
6 | module.exports = merge(baseConfig, {
7 | mode: 'development',
8 | // 开启监视模式, 此时执行webpack指令进行打包会监视文件变化自动打包
9 | // watch: true
10 | devServer: {
11 | open: true,
12 | hot: true, // 开启热更新
13 | compress: true,
14 | port: 3000,
15 | // contentBase: './src'
16 | proxy: {
17 | // /api/getUserInfo
18 | // 当前端请求 /api 地址时, 会将请求转发到
19 | // http://localhost:9999/api
20 | // 举例: 客户端现在请求的时 /api/getUserInfo
21 | // 此时会将请求转发到: http://localhost:9999/api/getUserInfo
22 | // '/api': 'http://localhost:9999',
23 | // 此时会将请求转发到: http://localhost:9999/getUserInfo
24 | // '/getUserInfo': 'http://localhost:9999'
25 | '/api': {
26 | target: 'http://localhost:9999',
27 | // 转发请求时不会携带 /api
28 | // http://localhost:9999/getUserInfo
29 | pathRewrite: {
30 | '^/api': ''
31 | }
32 | }
33 | }
34 | },
35 | devtool: 'cheap-module-eval-source-map',
36 | plugins: [
37 | new webpack.DefinePlugin({
38 | IS_DEV: 'true',
39 | // test: '1 + 1', // DefinePlugin会解析定义的环境变量表达式, 当成JS执行
40 | // test2: '"zs"'
41 | })
42 | ]
43 | })
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/build/webpack.dev.js:
--------------------------------------------------------------------------------
1 | const merge = require('webpack-merge')
2 | const baseConfig = require('./webpack.base.js')
3 | // 引入webpack
4 | const webpack = require('webpack')
5 | // webpack的配置文件遵循着CommonJS规范
6 | module.exports = merge(baseConfig, {
7 | mode: 'development',
8 | // 开启监视模式, 此时执行webpack指令进行打包会监视文件变化自动打包
9 | // watch: true
10 | devServer: {
11 | open: true,
12 | hot: true, // 开启热更新
13 | compress: true,
14 | port: 3000,
15 | // contentBase: './src'
16 | proxy: {
17 | // /api/getUserInfo
18 | // 当前端请求 /api 地址时, 会将请求转发到
19 | // http://localhost:9999/api
20 | // 举例: 客户端现在请求的时 /api/getUserInfo
21 | // 此时会将请求转发到: http://localhost:9999/api/getUserInfo
22 | // '/api': 'http://localhost:9999',
23 | // 此时会将请求转发到: http://localhost:9999/getUserInfo
24 | // '/getUserInfo': 'http://localhost:9999'
25 | '/api': {
26 | target: 'http://localhost:9999',
27 | // 转发请求时不会携带 /api
28 | // http://localhost:9999/getUserInfo
29 | pathRewrite: {
30 | '^/api': ''
31 | }
32 | }
33 | }
34 | },
35 | devtool: 'cheap-module-eval-source-map',
36 | plugins: [
37 | new webpack.DefinePlugin({
38 | IS_DEV: 'true',
39 | // test: '1 + 1', // DefinePlugin会解析定义的环境变量表达式, 当成JS执行
40 | // test2: '"zs"'
41 | })
42 | ]
43 | })
--------------------------------------------------------------------------------
/chapter5/itheima-pack/test/tapable-hellworld.js:
--------------------------------------------------------------------------------
1 | const { SyncHook } = require('tapable')
2 | // 来黑马学前端
3 | // 流程: 1.开班 2.学html 3.学css 4.学js 5.学react
4 | // 生命周期
5 | class Frontend {
6 | constructor() {
7 | // 1. 定义好钩子(定义生命周期)
8 | this.hooks = {
9 | // 如果需要在call时传参,则需要在new SyncHook时定义需要的参数
10 | beforeStudy: new SyncHook(),
11 | afterHtml: new SyncHook(),
12 | afterCss: new SyncHook(),
13 | afterJs: new SyncHook(),
14 | afterReact: new SyncHook(['name']),
15 | }
16 | }
17 | study() {
18 | // 2. 让钩子在指定阶段触发
19 | console.log('同学们好!!!开班啦!!!')
20 | this.hooks.beforeStudy.call()
21 |
22 | console.log('同学们好!!!开始学习html啦!!!')
23 | this.hooks.afterHtml.call()
24 | // 抽象化
25 |
26 | console.log('同学们好!!!开始学习css啦!!!')
27 | this.hooks.afterCss.call()
28 |
29 | console.log('同学们好!!!开始学习js啦!!!')
30 | this.hooks.afterJs.call()
31 |
32 | console.log('同学们好!!!开始学习react啦!!!')
33 | this.hooks.afterReact.call('紫阳')
34 | }
35 | }
36 |
37 | let f = new Frontend()
38 | // 3. 注册事件
39 | f.hooks.afterHtml.tap('afterHtml', () => {
40 | console.log('学完html后我想造淘宝!!!')
41 | })
42 | f.hooks.afterJs.tap('afterJs', () => {
43 | console.log('学完js后我想造webpack!!!')
44 | })
45 | f.hooks.afterReact.tap('afterReact', (name) => {
46 | console.log(name + '真牛逼!')
47 | console.log('学完react后我想造地球!!!')
48 | })
49 | f.study()
--------------------------------------------------------------------------------
/chapter2/webpack-basic/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-basic",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "buildcustom": "webpack --config webpack.custom.config.js",
9 | "build": "webpack",
10 | "watch": "webpack --watch",
11 | "dev2": "webpack-dev-server --compress --hot --port 5000 --open --contentBase src",
12 | "dev": "webpack-dev-server",
13 | "server": "node server.js"
14 | },
15 | "keywords": [],
16 | "author": "",
17 | "license": "ISC",
18 | "devDependencies": {
19 | "@babel/core": "^7.4.4",
20 | "@babel/plugin-proposal-class-properties": "^7.4.4",
21 | "@babel/plugin-transform-runtime": "^7.4.4",
22 | "@babel/preset-env": "^7.4.4",
23 | "babel-loader": "^8.0.5",
24 | "clean-webpack-plugin": "^2.0.2",
25 | "copy-webpack-plugin": "^5.0.3",
26 | "css-loader": "^2.1.1",
27 | "express": "^4.16.4",
28 | "file-loader": "^3.0.1",
29 | "html-webpack-plugin": "^3.2.0",
30 | "less": "^3.9.0",
31 | "less-loader": "^5.0.0",
32 | "node-sass": "^4.12.0",
33 | "sass-loader": "^7.1.0",
34 | "style-loader": "^0.23.1",
35 | "url-loader": "^1.1.2",
36 | "webpack": "^4.30.0",
37 | "webpack-cli": "^3.3.1",
38 | "webpack-dev-middleware": "^3.6.2",
39 | "webpack-dev-server": "^3.3.1"
40 | },
41 | "dependencies": {
42 | "@babel/polyfill": "^7.4.4",
43 | "@babel/runtime": "^7.4.4",
44 | "bootstrap": "^3.4.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/chapter5/webpack-demo/plugins/HTMLPlugin.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const cheerio = require('cheerio')
3 | module.exports = class HTMLPlugin {
4 | constructor(options) {
5 | // template filename
6 | this.options = options
7 | }
8 | apply(compiler) {
9 | // console.log(Object.keys(compiler))
10 | // 1. 注册`afterEmit`钩子
11 | compiler.hooks.afterEmit.tap('HTMLPlugin', compilation => {
12 | // console.log(Object.keys(compilation))
13 | // 如果大家使用done钩子 则需要使用stats.compilation.assets获取数据
14 | // console.log(...Object.keys(stats))
15 | // console.log(...Object.keys(stats.compilation.assets))
16 | // console.log(stats.hash)
17 | // console.log(stats.startTime)
18 | // console.log(stats.endTime)
19 | // 2. 根据创建对象时传入的template属性来读取html模板
20 | // console.log(this.options.template)
21 | let result = fs.readFileSync(this.options.template, 'utf-8')
22 | // 3. 使用工具分析HTML,推荐使用cheerio,可以直接使用jQuery api
23 | let $ = cheerio.load(result)
24 | // console.log(compilation.assets)
25 | // 4. 循环遍历webpack打包的资源文件列表,如果有多个bundle就都打包进去(可以根据需求自己修改,因为可能有chunk,一般只引入第一个即可)
26 | Object.keys(compilation.assets).forEach(item => $(``).appendTo('body'))
27 | // 5. 输出新生成的HTML字符串到dist目录中 (根据传入的filename来输出)
28 | // console.log($.html())
29 | // console.log('./dist/' + this.options.filename)
30 | // path.join(process.cwd(), 'dist', this.options.filename)
31 | fs.writeFileSync('./dist/' + this.options.filename, $.html())
32 | })
33 | }
34 | }
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/index.js:
--------------------------------------------------------------------------------
1 | console.log('我是index.js')
2 |
3 | // import $ from 'jquery' // node_modules/jquery/package.json > main
4 |
5 | // console.log($, jQuery)
6 |
7 | // console.log(window.$)
8 |
9 | // $('body').css('backgroundColor', 'green')
10 |
11 | // import { getUserInfo } from './api/http.js'
12 | // getUserInfo().then(() => { }, (err) => {
13 | // console.log(err)
14 | // })
15 |
16 | // console.log(IS_DEV, test, test2)
17 |
18 | // import axios from 'axios'
19 | // axios.get('/api/getUserInfo')
20 | // .then(result => console.log(result))
21 |
22 | // console.log('嘿嘿嘿233')
23 |
24 | // import str from './hotmodule.js'
25 | // console.log(str)
26 |
27 | // if (module.hot) {
28 | // module.hot.accept('./hotmodule.js', function () {
29 | // // 当hotmodule模块内容更新时触发
30 | // // console.log('hotmodule被更新了!')
31 | // // import / export语法必须在顶级作用域中使用,无法在子级作用域中使用
32 | // // import str from './hotmodule'
33 | // var hotmodule = require('./hotmodule.js')
34 | // console.log(hotmodule)
35 | // })
36 | // }
37 |
38 | // let math = require('./math.js')
39 | // console.log(math)
40 | // console.log(math.add(1, 2))
41 |
42 | // import { add } from './math.js'
43 | // console.log(add(1, 2))
44 |
45 | // if (xxx === yyy) {
46 | // import {add} from './math.js'
47 | // } else {
48 | // import {minus} from './math.js'
49 | // }
50 |
51 | // 动态导入 可以在if判断时进行导入
52 | // require()
53 |
54 | // let a = 1
55 | // let b = 2
56 | // let c = 3
57 | // console.log(a + b + c)
58 | // console.log(a, b, c)
59 |
60 | import {a, b, c} from './constant.js'
61 | // 类似于 预执行 将结果推断后打包放在这里
62 | console.log(a + b + c)
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/index.js:
--------------------------------------------------------------------------------
1 | console.log('我是index.js')
2 |
3 | // import $ from 'jquery' // node_modules/jquery/package.json > main
4 |
5 | // console.log($, jQuery)
6 |
7 | // console.log(window.$)
8 |
9 | // $('body').css('backgroundColor', 'green')
10 |
11 | // import { getUserInfo } from './api/http.js'
12 | // getUserInfo().then(() => { }, (err) => {
13 | // console.log(err)
14 | // })
15 |
16 | // console.log(IS_DEV, test, test2)
17 |
18 | // import axios from 'axios'
19 | // axios.get('/api/getUserInfo')
20 | // .then(result => console.log(result))
21 |
22 | // console.log('嘿嘿嘿233')
23 |
24 | // import str from './hotmodule.js'
25 | // console.log(str)
26 |
27 | // if (module.hot) {
28 | // module.hot.accept('./hotmodule.js', function () {
29 | // // 当hotmodule模块内容更新时触发
30 | // // console.log('hotmodule被更新了!')
31 | // // import / export语法必须在顶级作用域中使用,无法在子级作用域中使用
32 | // // import str from './hotmodule'
33 | // var hotmodule = require('./hotmodule.js')
34 | // console.log(hotmodule)
35 | // })
36 | // }
37 |
38 | // let math = require('./math.js')
39 | // console.log(math)
40 | // console.log(math.add(1, 2))
41 |
42 | // import { add } from './math.js'
43 | // console.log(add(1, 2))
44 |
45 | // if (xxx === yyy) {
46 | // import {add} from './math.js'
47 | // } else {
48 | // import {minus} from './math.js'
49 | // }
50 |
51 | // 动态导入 可以在if判断时进行导入
52 | // require()
53 |
54 | // let a = 1
55 | // let b = 2
56 | // let c = 3
57 | // console.log(a + b + c)
58 | // console.log(a, b, c)
59 |
60 | import {a, b, c} from './constant.js'
61 | // 类似于 预执行 将结果推断后打包放在这里
62 | console.log(a + b + c)
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-advanced",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "buildcustom": "webpack --config webpack.custom.config.js",
9 | "build": "webpack --config ./build/webpack.prod.js",
10 | "watch": "webpack --watch",
11 | "dev2": "webpack-dev-server --compress --hot --port 5000 --open --contentBase src",
12 | "dev": "webpack-dev-server --config ./build/webpack.dev.js",
13 | "server": "node server.js",
14 | "start": "live-server ./dist"
15 | },
16 | "keywords": [],
17 | "author": "",
18 | "license": "ISC",
19 | "devDependencies": {
20 | "@babel/core": "^7.4.4",
21 | "@babel/plugin-proposal-class-properties": "^7.4.4",
22 | "@babel/plugin-transform-runtime": "^7.4.4",
23 | "@babel/preset-env": "^7.4.4",
24 | "babel-loader": "^8.0.5",
25 | "clean-webpack-plugin": "^2.0.2",
26 | "copy-webpack-plugin": "^5.0.3",
27 | "css-loader": "^2.1.1",
28 | "expose-loader": "^0.7.5",
29 | "express": "^4.16.4",
30 | "file-loader": "^3.0.1",
31 | "html-webpack-plugin": "^3.2.0",
32 | "less": "^3.9.0",
33 | "less-loader": "^5.0.0",
34 | "live-server": "^1.2.1",
35 | "node-sass": "^4.12.0",
36 | "sass-loader": "^7.1.0",
37 | "style-loader": "^0.23.1",
38 | "url-loader": "^1.1.2",
39 | "webpack": "^4.30.0",
40 | "webpack-cli": "^3.3.1",
41 | "webpack-dev-middleware": "^3.6.2",
42 | "webpack-dev-server": "^3.3.1",
43 | "webpack-merge": "^4.2.1"
44 | },
45 | "dependencies": {
46 | "@babel/polyfill": "^7.4.4",
47 | "@babel/runtime": "^7.4.4",
48 | "axios": "^0.18.0",
49 | "bootstrap": "^3.4.1",
50 | "html-withimg-loader": "^0.1.16",
51 | "jquery": "^3.4.1"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-optimize",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "buildcustom": "webpack --config webpack.custom.config.js",
9 | "build": "webpack --config ./build/webpack.prod.js",
10 | "watch": "webpack --watch",
11 | "dev2": "webpack-dev-server --compress --hot --port 5000 --open --contentBase src",
12 | "dev": "webpack-dev-server --config ./build/webpack.dev.js",
13 | "server": "node server.js",
14 | "start": "live-server ./dist"
15 | },
16 | "keywords": [],
17 | "author": "",
18 | "license": "ISC",
19 | "devDependencies": {
20 | "@babel/core": "^7.4.4",
21 | "@babel/plugin-proposal-class-properties": "^7.4.4",
22 | "@babel/plugin-transform-runtime": "^7.4.4",
23 | "@babel/preset-env": "^7.4.4",
24 | "babel-loader": "^8.0.5",
25 | "clean-webpack-plugin": "^2.0.2",
26 | "copy-webpack-plugin": "^5.0.3",
27 | "css-loader": "^2.1.1",
28 | "expose-loader": "^0.7.5",
29 | "express": "^4.16.4",
30 | "file-loader": "^3.0.1",
31 | "html-webpack-plugin": "^3.2.0",
32 | "less": "^3.9.0",
33 | "less-loader": "^5.0.0",
34 | "live-server": "^1.2.1",
35 | "node-sass": "^4.12.0",
36 | "sass-loader": "^7.1.0",
37 | "style-loader": "^0.23.1",
38 | "url-loader": "^1.1.2",
39 | "webpack": "^4.30.0",
40 | "webpack-cli": "^3.3.1",
41 | "webpack-dev-middleware": "^3.6.2",
42 | "webpack-dev-server": "^3.3.1",
43 | "webpack-merge": "^4.2.1"
44 | },
45 | "dependencies": {
46 | "@babel/polyfill": "^7.4.4",
47 | "@babel/runtime": "^7.4.4",
48 | "axios": "^0.18.0",
49 | "bootstrap": "^3.4.1",
50 | "html-withimg-loader": "^0.1.16",
51 | "jquery": "^3.4.1"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/chapter2/webpack-basic/src/main.js:
--------------------------------------------------------------------------------
1 | // CommonJS规范 在浏览器中不支持
2 | // let a = require('./a.js')
3 |
4 | // ES6的导入导出语法规范
5 | import a from './a.js'
6 |
7 | // 引入css
8 | import './css/index.css'
9 | import './css/b.css'
10 |
11 | // 引入less
12 | import './less/index.less'
13 | // 引入sass
14 | import './scss/index.scss'
15 |
16 | // 引入bootstrap的css文件
17 | import 'bootstrap/dist/css/bootstrap.css'
18 |
19 | // console.log(a)
20 | // console.log('黑马程序员真牛逼!')
21 | // console.log('黑马程序员真牛逼! 是的牛逼!!!')
22 |
23 | // console.log('黑马程序员真牛逼! 是的牛逼!!!嘿嘿嘿')
24 | // console.log('黑马程序员真牛逼! 是的牛逼!!!嘿嘿嘿123567')
25 |
26 | // window.onload = function() {
27 | // document.querySelector('ul').style.listStyle = 'none'
28 | // document.querySelector('li').style.backgroundColor = 'yellow'
29 | // }
30 |
31 | // setTimeout(function() {
32 | // // 如果是function 内部this直接指向window
33 | // console.log('没用箭头函数, 一秒后我执行了')
34 | // }, 1000)
35 |
36 | // setTimeout(() => {
37 | // console.log('我是用了箭头函数的setTimeout')
38 | // }, 1000)
39 |
40 | // // ES6提供了class关键字 是原型的语法糖
41 | // class Person {
42 | // constructor (name) {
43 | // this.name = name
44 | // }
45 | // }
46 |
47 | // let p = new Person('小黑')
48 | // console.log(p)
49 |
50 | // class Dog {
51 | // // 创建Dog对象时默认的name为大黄
52 | // name = '大黄'
53 | // static color = 'yellow'
54 | // }
55 |
56 | // let d = new Dog()
57 | // console.dir(d)
58 | // console.dir(Dog)
59 |
60 | function *fn() {
61 | yield 1
62 | yield 2
63 | return 3
64 | }
65 |
66 | let newFn = fn()
67 | console.log(newFn.next()) // 1
68 | console.log(newFn.next()) // 2
69 | console.log(newFn.next()) // 3
70 | // console.log(newFn.next()) // undefined
71 |
72 | // let arr = []
73 | // arr.forEach()
74 | // arr.some()
75 | // arr.reduce()
76 | // arr.includes()
77 |
78 | import '@babel/polyfill'
79 |
80 | // String.prototype.indexOf
81 | let str = '123'
82 | // JS是一门动态语言, 在代码执行时可以随时为对象添加属性或方法
83 | // babel在看到对象调用方法时默认不会进行转换
84 | // includes这样的新方法, 默认不会转换
85 | console.log(str.includes('2'))
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/src/main.js:
--------------------------------------------------------------------------------
1 | // CommonJS规范 在浏览器中不支持
2 | // let a = require('./a.js')
3 |
4 | // ES6的导入导出语法规范
5 | import a from './a.js'
6 |
7 | // 引入css
8 | import './css/index.css'
9 | import './css/b.css'
10 |
11 | // 引入less
12 | import './less/index.less'
13 | // 引入sass
14 | import './scss/index.scss'
15 |
16 | // 引入bootstrap的css文件
17 | import 'bootstrap/dist/css/bootstrap.css'
18 |
19 | // console.log(a)
20 | // console.log('黑马程序员真牛逼!')
21 | // console.log('黑马程序员真牛逼! 是的牛逼!!!')
22 |
23 | // console.log('黑马程序员真牛逼! 是的牛逼!!!嘿嘿嘿')
24 | // console.log('黑马程序员真牛逼! 是的牛逼!!!嘿嘿嘿123567')
25 |
26 | // window.onload = function() {
27 | // document.querySelector('ul').style.listStyle = 'none'
28 | // document.querySelector('li').style.backgroundColor = 'yellow'
29 | // }
30 |
31 | // setTimeout(function() {
32 | // // 如果是function 内部this直接指向window
33 | // console.log('没用箭头函数, 一秒后我执行了')
34 | // }, 1000)
35 |
36 | // setTimeout(() => {
37 | // console.log('我是用了箭头函数的setTimeout')
38 | // }, 1000)
39 |
40 | // // ES6提供了class关键字 是原型的语法糖
41 | // class Person {
42 | // constructor (name) {
43 | // this.name = name
44 | // }
45 | // }
46 |
47 | // let p = new Person('小黑')
48 | // console.log(p)
49 |
50 | // class Dog {
51 | // // 创建Dog对象时默认的name为大黄
52 | // name = '大黄'
53 | // static color = 'yellow'
54 | // }
55 |
56 | // let d = new Dog()
57 | // console.dir(d)
58 | // console.dir(Dog)
59 |
60 | function *fn() {
61 | yield 1
62 | yield 2
63 | return 3
64 | }
65 |
66 | let newFn = fn()
67 | console.log(newFn.next()) // 1
68 | console.log(newFn.next()) // 2
69 | console.log(newFn.next()) // 3
70 | // console.log(newFn.next()) // undefined
71 |
72 | // let arr = []
73 | // arr.forEach()
74 | // arr.some()
75 | // arr.reduce()
76 | // arr.includes()
77 |
78 | import '@babel/polyfill'
79 |
80 | // String.prototype.indexOf
81 | let str = '123'
82 | // JS是一门动态语言, 在代码执行时可以随时为对象添加属性或方法
83 | // babel在看到对象调用方法时默认不会进行转换
84 | // includes这样的新方法, 默认不会转换
85 | console.log(str.includes('2'))
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/src/main.js:
--------------------------------------------------------------------------------
1 | // CommonJS规范 在浏览器中不支持
2 | // let a = require('./a.js')
3 |
4 | // ES6的导入导出语法规范
5 | import a from './a.js'
6 |
7 | // 引入css
8 | import './css/index.css'
9 | import './css/b.css'
10 |
11 | // 引入less
12 | import './less/index.less'
13 | // 引入sass
14 | import './scss/index.scss'
15 |
16 | // 引入bootstrap的css文件
17 | import 'bootstrap/dist/css/bootstrap.css'
18 |
19 | // console.log(a)
20 | // console.log('黑马程序员真牛逼!')
21 | // console.log('黑马程序员真牛逼! 是的牛逼!!!')
22 |
23 | // console.log('黑马程序员真牛逼! 是的牛逼!!!嘿嘿嘿')
24 | // console.log('黑马程序员真牛逼! 是的牛逼!!!嘿嘿嘿123567')
25 |
26 | // window.onload = function() {
27 | // document.querySelector('ul').style.listStyle = 'none'
28 | // document.querySelector('li').style.backgroundColor = 'yellow'
29 | // }
30 |
31 | // setTimeout(function() {
32 | // // 如果是function 内部this直接指向window
33 | // console.log('没用箭头函数, 一秒后我执行了')
34 | // }, 1000)
35 |
36 | // setTimeout(() => {
37 | // console.log('我是用了箭头函数的setTimeout')
38 | // }, 1000)
39 |
40 | // // ES6提供了class关键字 是原型的语法糖
41 | // class Person {
42 | // constructor (name) {
43 | // this.name = name
44 | // }
45 | // }
46 |
47 | // let p = new Person('小黑')
48 | // console.log(p)
49 |
50 | // class Dog {
51 | // // 创建Dog对象时默认的name为大黄
52 | // name = '大黄'
53 | // static color = 'yellow'
54 | // }
55 |
56 | // let d = new Dog()
57 | // console.dir(d)
58 | // console.dir(Dog)
59 |
60 | function *fn() {
61 | yield 1
62 | yield 2
63 | return 3
64 | }
65 |
66 | let newFn = fn()
67 | console.log(newFn.next()) // 1
68 | console.log(newFn.next()) // 2
69 | console.log(newFn.next()) // 3
70 | // console.log(newFn.next()) // undefined
71 |
72 | // let arr = []
73 | // arr.forEach()
74 | // arr.some()
75 | // arr.reduce()
76 | // arr.includes()
77 |
78 | import '@babel/polyfill'
79 |
80 | // String.prototype.indexOf
81 | let str = '123'
82 | // JS是一门动态语言, 在代码执行时可以随时为对象添加属性或方法
83 | // babel在看到对象调用方法时默认不会进行转换
84 | // includes这样的新方法, 默认不会转换
85 | console.log(str.includes('2'))
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-optimize",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "buildcustom": "webpack --config webpack.custom.config.js",
9 | "build": "webpack --config ./build/webpack.prod.js",
10 | "watch": "webpack --watch",
11 | "dev2": "webpack-dev-server --compress --hot --port 5000 --open --contentBase src",
12 | "dev": "webpack-dev-server --config ./build/webpack.dev.js",
13 | "server": "node server.js",
14 | "start": "live-server ./dist"
15 | },
16 | "keywords": [],
17 | "author": "",
18 | "license": "ISC",
19 | "devDependencies": {
20 | "@babel/core": "^7.4.4",
21 | "@babel/plugin-proposal-class-properties": "^7.4.4",
22 | "@babel/plugin-transform-runtime": "^7.4.4",
23 | "@babel/preset-env": "^7.4.4",
24 | "autoprefixer": "^9.5.1",
25 | "babel-loader": "^8.0.5",
26 | "clean-webpack-plugin": "^2.0.2",
27 | "copy-webpack-plugin": "^5.0.3",
28 | "css-loader": "^2.1.1",
29 | "expose-loader": "^0.7.5",
30 | "express": "^4.16.4",
31 | "file-loader": "^3.0.1",
32 | "html-webpack-plugin": "^3.2.0",
33 | "less": "^3.9.0",
34 | "less-loader": "^5.0.0",
35 | "live-server": "^1.2.1",
36 | "mini-css-extract-plugin": "^0.6.0",
37 | "node-sass": "^4.12.0",
38 | "optimize-css-assets-webpack-plugin": "^5.0.1",
39 | "postcss-loader": "^3.0.0",
40 | "sass-loader": "^7.1.0",
41 | "style-loader": "^0.23.1",
42 | "terser-webpack-plugin": "^1.2.4",
43 | "url-loader": "^1.1.2",
44 | "webpack": "^4.30.0",
45 | "webpack-cli": "^3.3.1",
46 | "webpack-dev-middleware": "^3.6.2",
47 | "webpack-dev-server": "^3.3.1",
48 | "webpack-merge": "^4.2.1"
49 | },
50 | "dependencies": {
51 | "@babel/polyfill": "^7.4.4",
52 | "@babel/runtime": "^7.4.4",
53 | "axios": "^0.18.0",
54 | "bootstrap": "^3.4.1",
55 | "html-withimg-loader": "^0.1.16",
56 | "jquery": "^3.4.1"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/src/main.js:
--------------------------------------------------------------------------------
1 | // import vue from 'vue' // runtime-only 的 vue 包
2 | // import Vue from 'vue/dist/vue.js' // 完整版的vuejs
3 | // import VueRouter from 'vue-router'
4 |
5 | // Vue.use(VueRouter)
6 |
7 | // const homeComponent = {
8 | // template: '我是homeaaa页面,你好哇!!!黑马程序员!!!!!!嘿嘿嘿!!!哇 好厉害哦!
'
9 | // }
10 |
11 | // const newsComponent = {
12 | // template: '我是newsheiheihei页面
'
13 | // }
14 |
15 | // const router = new VueRouter({
16 | // routes: [
17 | // {
18 | // path: '/home',
19 | // component: homeComponent
20 | // },
21 | // {
22 | // path: '/news',
23 | // component: newsComponent
24 | // }
25 | // ]
26 | // })
27 |
28 | // new Vue({
29 | // el: '#app',
30 | // data: {
31 | // msg: 'helloworld'
32 | // },
33 | // router
34 | // })
35 |
36 | // import moment from 'moment'
37 | // // 手动引入语言包
38 | // import 'moment/locale/zh-cn'
39 | // // 设置语言
40 | // moment.locale('zh-CN')
41 | // console.log(moment().subtract(6, 'days').calendar())
42 |
43 |
44 | // 静态导入
45 | // import $ from 'jquery'
46 | // import和export必须写在顶级作用域中,否则会报错,因为是静态导入
47 | // let a = 1
48 | // if (a = 1) {
49 | // import $ from 'jquery'
50 | // } else {
51 | // import $ from 'webpack'
52 | // }
53 |
54 | // import 'bootstrap'
55 |
56 | // 需求: 当用户点击按钮时 添加一个div
57 | // $(function() {
58 | // $('#btn').click(function() {
59 | // $('').html('我是main').appendTo('body')
60 | // })
61 | // })
62 |
63 | // import a from './a.js'
64 | // console.log(a.name)
65 |
66 | // window.onload = function() {
67 | // document.getElementById('btn').onclick = function() {
68 | // // 当用户点击按钮时才会执行
69 | // $('').html('我是main').appendTo('body')
70 | // }
71 | // }
72 |
73 |
74 | // import('jquery') 其实返回的就是一个promise对象
75 | // function getComponent() {
76 | // return import('jquery').then(({ default: $ }) => {
77 | // // 执行resolve时就表示jQuery导入完成了
78 | // return $('').html('我是main')
79 | // })
80 | // }
81 |
82 | // getComponent().then(item => {
83 | // item.appendTo('body')
84 | // })
85 |
86 |
87 |
88 | window.onload = function () {
89 | document.getElementById('btn').onclick = function () {
90 | // 当用户点击按钮时才会执行
91 | getComponent().then(item => {
92 | item.appendTo('body')
93 | })
94 | }
95 | }
96 |
97 | // 动态导入
98 | function getComponent() {
99 | return import(/* webpackPrefetch: true */ 'jquery').then(({ default: $ }) => {
100 | return $('').html('我是main')
101 | })
102 | }
--------------------------------------------------------------------------------
/chapter2/webpack-basic/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const HtmlWebpackPlugin = require('html-webpack-plugin')
3 | const CleanWebpackPlugin = require('clean-webpack-plugin')
4 | const CopyWebpackPlugin = require('copy-webpack-plugin')
5 | const webpack = require('webpack')
6 |
7 | // webpack的配置文件遵循着CommonJS规范
8 | module.exports = {
9 | entry: './src/main.js',
10 | output: {
11 | // path.resolve() : 解析当前相对路径的绝对路径
12 | // path: path.resolve('./dist/'),
13 | // path: path.resolve(__dirname, './dist/'),
14 | path: path.join(__dirname, './dist/'),
15 | filename: 'bundle.js',
16 | publicPath: '/'
17 | },
18 | mode: 'production',
19 | // 开启监视模式, 此时执行webpack指令进行打包会监视文件变化自动打包
20 | // watch: true
21 | devServer: {
22 | open: true,
23 | hot: true,
24 | compress: true,
25 | port: 3000,
26 | // contentBase: './src'
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | filename: 'index.html',
31 | template: './src/index.html'
32 | }),
33 | new CleanWebpackPlugin(),
34 | new CopyWebpackPlugin([
35 | {
36 | from: path.join(__dirname, 'assets'),
37 | to: 'assets'
38 | }
39 | ]),
40 | new webpack.BannerPlugin('黑马程序员真牛biubiu!')
41 | ],
42 | module: {
43 | rules: [
44 | {
45 | test: /\.css$/,
46 | // webpack读取loader时 是从右到左的读取, 会将css文件先交给最右侧的loader来处理
47 | // loader的执行顺序是从右到左以管道的方式链式调用
48 | // css-loader: 解析css文件
49 | // style-loader: 将解析出来的结果 放到html中, 使其生效
50 | use: ['style-loader', 'css-loader']
51 | },
52 | { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
53 | { test: /\.s(a|c)ss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
54 | {
55 | test: /\.(jpg|jpeg|png|bmp|gif)$/,
56 | use: {
57 | loader: 'url-loader',
58 | options: {
59 | limit: 5 * 1024,
60 | outputPath: 'images',
61 | name: '[name]-[hash:4].[ext]'
62 | }
63 | }
64 | },
65 | { test: /\.(woff|woff2|eot|svg|ttf)$/, use: 'url-loader' },
66 | {
67 | test: /\.js$/,
68 | use: {
69 | loader: 'babel-loader',
70 | // options: {
71 | // presets: ['@babel/env'],
72 | // plugins: [
73 | // '@babel/plugin-proposal-class-properties',
74 | // '@babel/plugin-transform-runtime'
75 | // ]
76 | // }
77 | },
78 | exclude: /node_modules/,
79 |
80 | }
81 | ]
82 | },
83 | // devtool: 'cheap-module-eval-source-map'
84 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-optimize",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "buildcustom": "webpack --config webpack.custom.config.js",
9 | "build": "webpack --config ./build/webpack.prod.js",
10 | "build:analyse": "webpack --profile --json > stats.json --config ./build/webpack.prod.js",
11 | "build:vue": "webpack --config ./build/webpack.vue.js",
12 | "build:react": "webpack --config ./build/webpack.react.js",
13 | "dev-build": "webpack --config ./build/webpack.dev.js",
14 | "watch": "webpack --watch",
15 | "dev2": "webpack-dev-server --compress --hot --port 5000 --open --contentBase src",
16 | "dev": "webpack-dev-server --config ./build/webpack.dev.js",
17 | "server": "node server.js",
18 | "start": "live-server ./dist"
19 | },
20 | "keywords": [],
21 | "author": "",
22 | "license": "ISC",
23 | "devDependencies": {
24 | "@babel/core": "^7.4.4",
25 | "@babel/plugin-proposal-class-properties": "^7.4.4",
26 | "@babel/plugin-syntax-dynamic-import": "^7.2.0",
27 | "@babel/plugin-transform-runtime": "^7.4.4",
28 | "@babel/preset-env": "^7.4.4",
29 | "add-asset-html-webpack-plugin": "^3.1.3",
30 | "autoprefixer": "^9.5.1",
31 | "babel-loader": "^8.0.5",
32 | "clean-webpack-plugin": "^2.0.2",
33 | "copy-webpack-plugin": "^5.0.3",
34 | "css-loader": "^2.1.1",
35 | "expose-loader": "^0.7.5",
36 | "express": "^4.16.4",
37 | "file-loader": "^3.0.1",
38 | "happypack": "^5.0.1",
39 | "html-webpack-plugin": "^3.2.0",
40 | "less": "^3.9.0",
41 | "less-loader": "^5.0.0",
42 | "live-server": "^1.2.1",
43 | "mini-css-extract-plugin": "^0.6.0",
44 | "node-sass": "^4.12.0",
45 | "optimize-css-assets-webpack-plugin": "^5.0.1",
46 | "postcss-loader": "^3.0.0",
47 | "sass-loader": "^7.1.0",
48 | "style-loader": "^0.23.1",
49 | "terser-webpack-plugin": "^1.2.4",
50 | "url-loader": "^1.1.2",
51 | "webpack": "^4.30.0",
52 | "webpack-bundle-analyzer": "^3.3.2",
53 | "webpack-cli": "^3.3.1",
54 | "webpack-dev-middleware": "^3.6.2",
55 | "webpack-dev-server": "^3.3.1",
56 | "webpack-merge": "^4.2.1"
57 | },
58 | "dependencies": {
59 | "@babel/polyfill": "^7.4.4",
60 | "@babel/runtime": "^7.4.4",
61 | "axios": "^0.18.0",
62 | "bootstrap": "^3.4.1",
63 | "html-withimg-loader": "^0.1.16",
64 | "jquery": "^3.4.1",
65 | "moment": "^2.24.0",
66 | "react": "^16.8.6",
67 | "react-dom": "^16.8.6",
68 | "vue": "^2.6.10",
69 | "vue-router": "^3.0.6"
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/chapter3/webpack-advanced/build/webpack.base.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const HtmlWebpackPlugin = require('html-webpack-plugin')
3 | const CleanWebpackPlugin = require('clean-webpack-plugin')
4 | const CopyWebpackPlugin = require('copy-webpack-plugin')
5 | const webpack = require('webpack')
6 |
7 | // webpack的配置文件遵循着CommonJS规范
8 | module.exports = {
9 | // entry: './src/main.js',
10 | entry: {
11 | index: './src/index.js',
12 | other: './src/other.js'
13 | },
14 | output: {
15 | // path.resolve() : 解析当前相对路径的绝对路径
16 | // path: path.resolve('./dist/'),
17 | // path: path.resolve(__dirname, './dist/'),
18 | path: path.join(__dirname, '..', './dist/'),
19 | // filename: 'bundle.js',
20 | filename: '[name].js',
21 | publicPath: '/'
22 | },
23 | // 开启监视模式, 此时执行webpack指令进行打包会监视文件变化自动打包
24 | // watch: true
25 | plugins: [
26 | new HtmlWebpackPlugin({
27 | filename: 'index.html',
28 | template: './src/index.html',
29 | chunks: ['index', 'other']
30 | }),
31 | new HtmlWebpackPlugin({
32 | filename: 'other.html',
33 | template: './src/other.html',
34 | chunks: ['other']
35 | }),
36 | new CleanWebpackPlugin(),
37 | new CopyWebpackPlugin([
38 | {
39 | from: path.join(__dirname, '..', 'assets'),
40 | to: 'assets'
41 | }
42 | ]),
43 | new webpack.BannerPlugin('黑马程序员真牛biubiu!'),
44 | new webpack.ProvidePlugin({
45 | $: 'jquery',
46 | jQuery: 'jquery'
47 | })
48 | ],
49 | module: {
50 | rules: [
51 | {
52 | test: /\.css$/,
53 | // webpack读取loader时 是从右到左的读取, 会将css文件先交给最右侧的loader来处理
54 | // loader的执行顺序是从右到左以管道的方式链式调用
55 | // css-loader: 解析css文件
56 | // style-loader: 将解析出来的结果 放到html中, 使其生效
57 | use: ['style-loader', 'css-loader']
58 | },
59 | { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
60 | { test: /\.s(a|c)ss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
61 | {
62 | test: /\.(jpg|jpeg|png|bmp|gif)$/,
63 | use: {
64 | loader: 'url-loader',
65 | options: {
66 | limit: 5 * 1024,
67 | outputPath: 'images',
68 | name: '[name]-[hash:6].[ext]'
69 | }
70 | }
71 | },
72 | { test: /\.(woff|woff2|eot|svg|ttf)$/, use: 'url-loader' },
73 | {
74 | test: /\.js$/,
75 | use: {
76 | loader: 'babel-loader',
77 | // options: {
78 | // presets: ['@babel/env'],
79 | // plugins: [
80 | // '@babel/plugin-proposal-class-properties',
81 | // '@babel/plugin-transform-runtime'
82 | // ]
83 | // }
84 | },
85 | exclude: /node_modules/,
86 |
87 | },
88 | {
89 | test: /\.(htm|html)$/i,
90 | loader: 'html-withimg-loader'
91 | },
92 | // {
93 | // // 用于解析jQuery模块的绝对路径
94 | // test: require.resolve('jquery'),
95 | // use: {
96 | // loader: 'expose-loader',
97 | // options: '$'
98 | // }
99 | // }
100 | ]
101 | }
102 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize/build/webpack.base.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const HtmlWebpackPlugin = require('html-webpack-plugin')
3 | const CleanWebpackPlugin = require('clean-webpack-plugin')
4 | const CopyWebpackPlugin = require('copy-webpack-plugin')
5 | const webpack = require('webpack')
6 |
7 | // webpack的配置文件遵循着CommonJS规范
8 | module.exports = {
9 | // entry: './src/main.js',
10 | entry: {
11 | index: './src/index.js',
12 | other: './src/other.js'
13 | },
14 | output: {
15 | // path.resolve() : 解析当前相对路径的绝对路径
16 | // path: path.resolve('./dist/'),
17 | // path: path.resolve(__dirname, './dist/'),
18 | path: path.join(__dirname, '..', './dist/'),
19 | // filename: 'bundle.js',
20 | filename: '[name].js',
21 | publicPath: '/'
22 | },
23 | // 开启监视模式, 此时执行webpack指令进行打包会监视文件变化自动打包
24 | // watch: true
25 | plugins: [
26 | new HtmlWebpackPlugin({
27 | filename: 'index.html',
28 | template: './src/index.html',
29 | chunks: ['index', 'other']
30 | }),
31 | new HtmlWebpackPlugin({
32 | filename: 'other.html',
33 | template: './src/other.html',
34 | chunks: ['other']
35 | }),
36 | new CleanWebpackPlugin(),
37 | new CopyWebpackPlugin([
38 | {
39 | from: path.join(__dirname, '..', 'assets'),
40 | to: 'assets'
41 | }
42 | ]),
43 | new webpack.BannerPlugin('黑马程序员真牛biubiu!'),
44 | new webpack.ProvidePlugin({
45 | $: 'jquery',
46 | jQuery: 'jquery'
47 | })
48 | ],
49 | module: {
50 | rules: [
51 | {
52 | test: /\.css$/,
53 | // webpack读取loader时 是从右到左的读取, 会将css文件先交给最右侧的loader来处理
54 | // loader的执行顺序是从右到左以管道的方式链式调用
55 | // css-loader: 解析css文件
56 | // style-loader: 将解析出来的结果 放到html中, 使其生效
57 | use: ['style-loader', 'css-loader']
58 | },
59 | { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
60 | { test: /\.s(a|c)ss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
61 | {
62 | test: /\.(jpg|jpeg|png|bmp|gif)$/,
63 | use: {
64 | loader: 'url-loader',
65 | options: {
66 | limit: 5 * 1024,
67 | outputPath: 'images',
68 | name: '[name]-[hash:6].[ext]'
69 | }
70 | }
71 | },
72 | { test: /\.(woff|woff2|eot|svg|ttf)$/, use: 'url-loader' },
73 | {
74 | test: /\.js$/,
75 | use: {
76 | loader: 'babel-loader',
77 | // options: {
78 | // presets: ['@babel/env'],
79 | // plugins: [
80 | // '@babel/plugin-proposal-class-properties',
81 | // '@babel/plugin-transform-runtime'
82 | // ]
83 | // }
84 | },
85 | exclude: /node_modules/,
86 |
87 | },
88 | {
89 | test: /\.(htm|html)$/i,
90 | loader: 'html-withimg-loader'
91 | },
92 | // {
93 | // // 用于解析jQuery模块的绝对路径
94 | // test: require.resolve('jquery'),
95 | // use: {
96 | // loader: 'expose-loader',
97 | // options: '$'
98 | // }
99 | // }
100 | ]
101 | }
102 | }
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-css/build/webpack.base.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const HtmlWebpackPlugin = require('html-webpack-plugin')
3 | const CleanWebpackPlugin = require('clean-webpack-plugin')
4 | const CopyWebpackPlugin = require('copy-webpack-plugin')
5 | const webpack = require('webpack')
6 | const MiniCssExtractPlugin = require('mini-css-extract-plugin')
7 |
8 | // webpack的配置文件遵循着CommonJS规范
9 | module.exports = {
10 | entry: './src/main.js',
11 | output: {
12 | // path.resolve() : 解析当前相对路径的绝对路径
13 | // path: path.resolve('./dist/'),
14 | // path: path.resolve(__dirname, './dist/'),
15 | path: path.join(__dirname, '..', './dist/'),
16 | // filename: 'bundle.js',
17 | filename: '[name].js',
18 | publicPath: '/'
19 | },
20 | // 开启监视模式, 此时执行webpack指令进行打包会监视文件变化自动打包
21 | // watch: true
22 | plugins: [
23 | new HtmlWebpackPlugin({
24 | filename: 'index.html',
25 | template: './src/index.html'
26 | }),
27 | new CleanWebpackPlugin(),
28 | new CopyWebpackPlugin([
29 | {
30 | from: path.join(__dirname, '..', 'assets'),
31 | to: 'assets'
32 | }
33 | ]),
34 | new webpack.BannerPlugin('黑马程序员真牛biubiu!'),
35 | new webpack.ProvidePlugin({
36 | $: 'jquery',
37 | jQuery: 'jquery'
38 | }),
39 | new MiniCssExtractPlugin({
40 | // placeholders
41 | filename: '[name].css'
42 | })
43 | ],
44 | module: {
45 | rules: [
46 | {
47 | test: /\.css$/,
48 | // webpack读取loader时 是从右到左的读取, 会将css文件先交给最右侧的loader来处理
49 | // loader的执行顺序是从右到左以管道的方式链式调用
50 | // css-loader: 解析css文件
51 | // style-loader: 将解析出来的结果 放到html中, 使其生效
52 | // use: ['style-loader', 'css-loader']
53 | use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']
54 | },
55 | // { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
56 | { test: /\.less$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader'] },
57 | // { test: /\.s(a|c)ss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
58 | { test: /\.s(a|c)ss$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'] },
59 | {
60 | test: /\.(jpg|jpeg|png|bmp|gif)$/,
61 | use: {
62 | loader: 'url-loader',
63 | options: {
64 | limit: 5 * 1024,
65 | outputPath: 'images',
66 | name: '[name]-[hash:6].[ext]'
67 | }
68 | }
69 | },
70 | { test: /\.(woff|woff2|eot|svg|ttf)$/, use: 'url-loader' },
71 | {
72 | test: /\.js$/,
73 | use: {
74 | loader: 'babel-loader',
75 | // options: {
76 | // presets: ['@babel/env'],
77 | // plugins: [
78 | // '@babel/plugin-proposal-class-properties',
79 | // '@babel/plugin-transform-runtime'
80 | // ]
81 | // }
82 | },
83 | exclude: /node_modules/,
84 |
85 | },
86 | {
87 | test: /\.(htm|html)$/i,
88 | loader: 'html-withimg-loader'
89 | },
90 | // {
91 | // // 用于解析jQuery模块的绝对路径
92 | // test: require.resolve('jquery'),
93 | // use: {
94 | // loader: 'expose-loader',
95 | // options: '$'
96 | // }
97 | // }
98 | ]
99 | }
100 | }
--------------------------------------------------------------------------------
/chapter5/itheima-pack/lib/Compiler.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const fs = require('fs')
3 | const parser = require('@babel/parser')
4 | const traverse = require('@babel/traverse').default
5 | const generator = require('@babel/generator').default
6 | const ejs = require('ejs')
7 | const { SyncHook } = require('tapable')
8 | class Compiler {
9 | constructor(config) {
10 | this.config = config
11 | this.entry = config.entry
12 | // 获取执行itheima-pack指令的目录
13 | this.root = process.cwd()
14 | // 初始化一个空对象, 存放所有的模块
15 | this.modules = {}
16 | // 将module.rules挂载到自身
17 | this.rules = config.module.rules
18 | // 先有hooks 才能调用apply
19 | this.hooks = {
20 | // 生命周期钩子的定义 ---> 第一步
21 | compile: new SyncHook(),
22 | afterCompile: new SyncHook(),
23 | emit: new SyncHook(),
24 | afterEmit: new SyncHook(),
25 | done: new SyncHook(['modules']),
26 | }
27 | // 获取plugins数组中的所有插件对象, 调用其apply方法
28 | if (Array.isArray(this.config.plugins)) {
29 | this.config.plugins.forEach(plugin => plugin.apply(this))
30 | }
31 | }
32 | getSource(path) {
33 | return fs.readFileSync(path, 'utf-8')
34 | }
35 | depAnalyse(modulePath) {
36 | // console.log(modulePath)
37 | // 读取模块内容
38 | let source = this.getSource(modulePath)
39 | // console.log(source)
40 |
41 | // 读取loader
42 | let readAndCallLoader = (use, obj) => {
43 | let loaderPath = path.join(this.root, use)
44 | let loader = require(loaderPath)
45 | source = loader.call(obj, source)
46 | }
47 |
48 | // 读取rules规则, 倒序遍历
49 | for (let i = this.rules.length - 1; i >= 0; i--) {
50 | // console.log(this.rules[i])
51 | let { test, use } = this.rules[i]
52 | // 获取每一条规则,与当前modulePath进行匹配
53 | // 匹配modulePath 是否符合规则,如果符合规则就要倒序遍历获取所有的loader
54 | if (test.test(modulePath)) {
55 | // 判断use是否为数组,如果是数组才需要倒序遍历
56 | if (Array.isArray(use)) {
57 | for (let j = use.length - 1; j >= 0; j--) {
58 | // 每一个loader的路径
59 | // console.log(path.join(this.root, use[j]))
60 | // let loaderPath = path.join(this.root, use[j])
61 | // let loader = require(loaderPath)
62 | // source = loader(source)
63 | readAndCallLoader(use[j])
64 | }
65 | } else if (typeof use === 'string') {
66 | // use为字符串时,直接加载loader即可
67 | // let loaderPath = path.join(this.root, use)
68 | // let loader = require(loaderPath)
69 | // source = loader(source)
70 | readAndCallLoader(use)
71 | } else if (use instanceof Object) {
72 | // console.log(use.options)
73 | // let loaderPath = path.join(this.root, use.loader)
74 | // let loader = require(loaderPath)
75 | // source = loader.call({ query: use.options }, source)
76 | readAndCallLoader(use.loader, { query: use.options })
77 | }
78 | }
79 | }
80 |
81 | // 准备一个依赖数组,用于存储当前模块的所有依赖
82 | let dependencies = []
83 |
84 | let ast = parser.parse(source)
85 | // console.log(ast.program.body)
86 | traverse(ast, {
87 | CallExpression(p) {
88 | if (p.node.callee.name === 'require') {
89 | // 修改require
90 | p.node.callee.name = '__webpack_require__'
91 |
92 | // 修改路径
93 | let oldValue = p.node.arguments[0].value
94 | oldValue = './' + path.join('src', oldValue)
95 | // 避免Windows出现反斜杠 : \
96 | p.node.arguments[0].value = oldValue.replace(/\\+/g, '/')
97 |
98 | // 每找到一个require调用, 就将其中的路径修改完毕后加入到依赖数组中
99 | dependencies.push(p.node.arguments[0].value)
100 | }
101 | }
102 | })
103 | let sourceCode = generator(ast).code
104 |
105 | // console.log(sourceCode)
106 |
107 | // 构建modules对象
108 | // { './src/index.js': 'xxxx', './src/news.js': 'yyyy' }
109 | // this.modules
110 | let modulePathRelative = './' + path.relative(this.root, modulePath)
111 | modulePathRelative = modulePathRelative.replace(/\\+/g, '/')
112 | this.modules[modulePathRelative] = sourceCode
113 |
114 | // 递归加载所有依赖
115 | // ./src/news.js ./src/news2.js
116 | dependencies.forEach(dep => this.depAnalyse(path.resolve(this.root, dep)))
117 | }
118 | emitFile() {
119 | // 使用模板进行拼接字符串,生成最终的结果代码
120 | let template = this.getSource(path.join(__dirname, '../template/output.ejs'))
121 | let result = ejs.render(template, {
122 | entry: this.entry,
123 | modules: this.modules
124 | })
125 | // 获取输出目录
126 | let outputPath = path.join(this.config.output.path, this.config.output.filename)
127 | fs.writeFileSync(outputPath, result)
128 | }
129 | start() {
130 | // 开始编译啦!
131 | this.hooks.compile.call()
132 | // 开始打包了!
133 | // 依赖的分析
134 | // __dirname表示的是 itheima-pack 项目中Compiler.js所在目录
135 | // 而非入口文件所在的目录
136 | // 如果需要获取执行itheima-pack指令的目录, 需要使用 process.cwd()
137 | this.depAnalyse(path.resolve(this.root, this.entry))
138 | // 编译完成啦!
139 | this.hooks.afterCompile.call()
140 | // 开始发射文件啦!
141 | this.hooks.emit.call()
142 | this.emitFile()
143 | // 文件发射完了!
144 | this.hooks.afterEmit.call()
145 | this.hooks.done.call(this.modules)
146 | // console.log(this.modules)
147 | }
148 | }
149 |
150 | module.exports = Compiler
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/build/webpack.base.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const HtmlWebpackPlugin = require('html-webpack-plugin')
3 | const CleanWebpackPlugin = require('clean-webpack-plugin')
4 | const CopyWebpackPlugin = require('copy-webpack-plugin')
5 | const webpack = require('webpack')
6 | const MiniCssExtractPlugin = require('mini-css-extract-plugin')
7 | const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
8 | const HappyPack = require('happypack')
9 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
10 |
11 | // webpack的配置文件遵循着CommonJS规范
12 | module.exports = {
13 | optimization: {
14 | splitChunks: {
15 | chunks: 'all', // 默认值为 async 表示只会对异步加载的模块进行代码分割
16 | minSize: 0, // 模块最少大于30KB才拆分
17 | maxSize: 0, // 如果超出了maxSize,会进一步进行拆分
18 | minChunks: 1, // 模块最少引用一次才会被拆分
19 | maxAsyncRequests: 5, // 异步加载时同时发送的请求数量最大不能超过5,超过5的部分不拆分
20 | maxInitialRequests: 3, // 页面初始化时同时发送的请求数量最大不能超过3,超过3的部分不拆分
21 | automaticNameDelimiter: '~', // 默认的连接符
22 | name: true, // 拆分的chunk名,设为true表示根据模块名和CacheGroups的key来自动生成,使用上面连接符连接
23 | cacheGroups: { // 缓存组配置,上面配置读取完成后进行拆分,如果需要把多个模块拆分到一个文件,就需要缓存,所以命名为缓存组
24 | vendors: { // 自定义缓存组名
25 | test: /[\\/]node_modules[\\/]/, // 检查node_modules目录,只要模块在该目录下就使用上面配置拆分到这个组
26 | priority: -10, // 权重-10,决定了哪个组优先匹配,例如node_modules下有个模块要拆分,同时满足vendors和default组,此时就会分到vendors组,因为-10 > -20
27 | // filename: 'vendors.js'
28 | },
29 | default: { // 默认缓存组名
30 | minChunks: 2, // 最少引用两次才会被拆分
31 | priority: -20, // 权重-20
32 | reuseExistingChunk: true // 如果主入口中引入了两个模块,其中一个正好也引用了后一个,就会直接复用,无需引用两次
33 | }
34 | }
35 | }
36 | },
37 | entry: {
38 | main: './src/main.js'
39 | // main: './src/main.react.js'
40 | },
41 | // entry: {
42 | // main: './src/main.js',
43 | // other: './src/other.js'
44 | // },
45 | output: {
46 | // path.resolve() : 解析当前相对路径的绝对路径
47 | // path: path.resolve('./dist/'),
48 | // path: path.resolve(__dirname, './dist/'),
49 | path: path.join(__dirname, '..', './dist/'),
50 | // filename: 'bundle.js',
51 | filename: '[name].[contenthash:8].bundle.js',
52 | publicPath: '/'
53 | },
54 | // 开启监视模式, 此时执行webpack指令进行打包会监视文件变化自动打包
55 | // watch: true
56 | plugins: [
57 | new HtmlWebpackPlugin({
58 | filename: 'index.html',
59 | template: './src/index.html'
60 | }),
61 | // new CleanWebpackPlugin(),
62 | new CopyWebpackPlugin([
63 | {
64 | from: path.join(__dirname, '..', 'assets'),
65 | to: 'assets'
66 | }
67 | ]),
68 | new webpack.BannerPlugin('黑马程序员真牛biubiu!'),
69 | new webpack.ProvidePlugin({
70 | $: 'jquery',
71 | jQuery: 'jquery'
72 | }),
73 | new MiniCssExtractPlugin({
74 | // placeholders
75 | filename: '[name].css'
76 | }),
77 | new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
78 | // new webpack.DllReferencePlugin({
79 | // manifest: path.resolve(__dirname, '../dist/manifest.json')
80 | // }),
81 | // new AddAssetHtmlWebpackPlugin({
82 | // filepath: path.resolve(__dirname, '../dist/vue_dll.js')
83 | // }),
84 | // new HappyPack({
85 | // loaders: ['babel-loader']
86 | // })
87 | // new BundleAnalyzerPlugin()
88 | ],
89 | module: {
90 | noParse: /jquery|bootstrap/,
91 | rules: [
92 | {
93 | test: /\.css$/,
94 | // webpack读取loader时 是从右到左的读取, 会将css文件先交给最右侧的loader来处理
95 | // loader的执行顺序是从右到左以管道的方式链式调用
96 | // css-loader: 解析css文件
97 | // style-loader: 将解析出来的结果 放到html中, 使其生效
98 | // use: ['style-loader', 'css-loader']
99 | use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']
100 | },
101 | // { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
102 | { test: /\.less$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader'] },
103 | // { test: /\.s(a|c)ss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
104 | { test: /\.s(a|c)ss$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'] },
105 | {
106 | test: /\.(jpg|jpeg|png|bmp|gif)$/,
107 | use: {
108 | loader: 'url-loader',
109 | options: {
110 | limit: 5 * 1024,
111 | outputPath: 'images',
112 | name: '[name]-[hash:6].[ext]'
113 | }
114 | }
115 | },
116 | { test: /\.(woff|woff2|eot|svg|ttf)$/, use: 'url-loader' },
117 | {
118 | test: /\.js$/,
119 | use: {
120 | // loader: 'happypack/loader',
121 | loader: 'babel-loader',
122 | // options: {
123 | // presets: ['@babel/env'],
124 | // plugins: [
125 | // '@babel/plugin-proposal-class-properties',
126 | // '@babel/plugin-transform-runtime'
127 | // ]
128 | // }
129 | },
130 | exclude: /node_modules/,
131 | include: path.resolve(__dirname, '../src')
132 | },
133 | {
134 | test: /\.(htm|html)$/i,
135 | loader: 'html-withimg-loader'
136 | },
137 | // {
138 | // // 用于解析jQuery模块的绝对路径
139 | // test: require.resolve('jquery'),
140 | // use: {
141 | // loader: 'expose-loader',
142 | // options: '$'
143 | // }
144 | // }
145 | ]
146 | }
147 | }
--------------------------------------------------------------------------------
/chapter5/itheima-pack/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "itheima-pack",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@babel/code-frame": {
8 | "version": "7.0.0",
9 | "resolved": "http://r.cnpmjs.org/@babel/code-frame/download/@babel/code-frame-7.0.0.tgz",
10 | "integrity": "sha1-BuKrGb21NThVWaq7W6WXKUgoAPg=",
11 | "requires": {
12 | "@babel/highlight": "^7.0.0"
13 | }
14 | },
15 | "@babel/generator": {
16 | "version": "7.4.4",
17 | "resolved": "http://r.cnpmjs.org/@babel/generator/download/@babel/generator-7.4.4.tgz",
18 | "integrity": "sha1-F0ohXrhD/DksftyqvqqHPebo8EE=",
19 | "requires": {
20 | "@babel/types": "^7.4.4",
21 | "jsesc": "^2.5.1",
22 | "lodash": "^4.17.11",
23 | "source-map": "^0.5.0",
24 | "trim-right": "^1.0.1"
25 | }
26 | },
27 | "@babel/helper-function-name": {
28 | "version": "7.1.0",
29 | "resolved": "http://r.cnpmjs.org/@babel/helper-function-name/download/@babel/helper-function-name-7.1.0.tgz",
30 | "integrity": "sha1-oM6wFoX3M1XUNgwSR/WCv6/I/1M=",
31 | "requires": {
32 | "@babel/helper-get-function-arity": "^7.0.0",
33 | "@babel/template": "^7.1.0",
34 | "@babel/types": "^7.0.0"
35 | }
36 | },
37 | "@babel/helper-get-function-arity": {
38 | "version": "7.0.0",
39 | "resolved": "http://r.cnpmjs.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.0.0.tgz",
40 | "integrity": "sha1-g1ctQyDipGVyY3NBE8QoaLZOScM=",
41 | "requires": {
42 | "@babel/types": "^7.0.0"
43 | }
44 | },
45 | "@babel/helper-split-export-declaration": {
46 | "version": "7.4.4",
47 | "resolved": "http://r.cnpmjs.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.4.4.tgz",
48 | "integrity": "sha1-/5SJSjQL549T8GrwOLIFxJ2ZNnc=",
49 | "requires": {
50 | "@babel/types": "^7.4.4"
51 | }
52 | },
53 | "@babel/highlight": {
54 | "version": "7.0.0",
55 | "resolved": "http://r.cnpmjs.org/@babel/highlight/download/@babel/highlight-7.0.0.tgz",
56 | "integrity": "sha1-9xDDjI1Fjm3ZogGvtjf8t4HOmeQ=",
57 | "requires": {
58 | "chalk": "^2.0.0",
59 | "esutils": "^2.0.2",
60 | "js-tokens": "^4.0.0"
61 | }
62 | },
63 | "@babel/parser": {
64 | "version": "7.4.5",
65 | "resolved": "http://r.cnpmjs.org/@babel/parser/download/@babel/parser-7.4.5.tgz",
66 | "integrity": "sha1-BK+NXVorBEoqG/+sweXmZzVE6HI="
67 | },
68 | "@babel/template": {
69 | "version": "7.4.4",
70 | "resolved": "http://r.cnpmjs.org/@babel/template/download/@babel/template-7.4.4.tgz",
71 | "integrity": "sha1-9LiNEiVomgj1vDoXSDVFvp5O0jc=",
72 | "requires": {
73 | "@babel/code-frame": "^7.0.0",
74 | "@babel/parser": "^7.4.4",
75 | "@babel/types": "^7.4.4"
76 | }
77 | },
78 | "@babel/traverse": {
79 | "version": "7.4.5",
80 | "resolved": "http://r.cnpmjs.org/@babel/traverse/download/@babel/traverse-7.4.5.tgz",
81 | "integrity": "sha1-TpLRco/S8Yl9r90yHvv/khVsMhY=",
82 | "requires": {
83 | "@babel/code-frame": "^7.0.0",
84 | "@babel/generator": "^7.4.4",
85 | "@babel/helper-function-name": "^7.1.0",
86 | "@babel/helper-split-export-declaration": "^7.4.4",
87 | "@babel/parser": "^7.4.5",
88 | "@babel/types": "^7.4.4",
89 | "debug": "^4.1.0",
90 | "globals": "^11.1.0",
91 | "lodash": "^4.17.11"
92 | }
93 | },
94 | "@babel/types": {
95 | "version": "7.4.4",
96 | "resolved": "http://r.cnpmjs.org/@babel/types/download/@babel/types-7.4.4.tgz",
97 | "integrity": "sha1-jbnppim7fCk3AAm0t3ntk/5X1fA=",
98 | "requires": {
99 | "esutils": "^2.0.2",
100 | "lodash": "^4.17.11",
101 | "to-fast-properties": "^2.0.0"
102 | }
103 | },
104 | "ansi-styles": {
105 | "version": "3.2.1",
106 | "resolved": "http://r.cnpmjs.org/ansi-styles/download/ansi-styles-3.2.1.tgz",
107 | "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=",
108 | "requires": {
109 | "color-convert": "^1.9.0"
110 | }
111 | },
112 | "chalk": {
113 | "version": "2.4.2",
114 | "resolved": "http://r.cnpmjs.org/chalk/download/chalk-2.4.2.tgz",
115 | "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=",
116 | "requires": {
117 | "ansi-styles": "^3.2.1",
118 | "escape-string-regexp": "^1.0.5",
119 | "supports-color": "^5.3.0"
120 | }
121 | },
122 | "color-convert": {
123 | "version": "1.9.3",
124 | "resolved": "http://r.cnpmjs.org/color-convert/download/color-convert-1.9.3.tgz",
125 | "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=",
126 | "requires": {
127 | "color-name": "1.1.3"
128 | }
129 | },
130 | "color-name": {
131 | "version": "1.1.3",
132 | "resolved": "http://r.cnpmjs.org/color-name/download/color-name-1.1.3.tgz",
133 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
134 | },
135 | "debug": {
136 | "version": "4.1.1",
137 | "resolved": "http://r.cnpmjs.org/debug/download/debug-4.1.1.tgz",
138 | "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=",
139 | "requires": {
140 | "ms": "^2.1.1"
141 | }
142 | },
143 | "ejs": {
144 | "version": "2.6.1",
145 | "resolved": "http://r.cnpmjs.org/ejs/download/ejs-2.6.1.tgz",
146 | "integrity": "sha1-SY7A1JVlWrxvI81hho2SZGQHGqA="
147 | },
148 | "escape-string-regexp": {
149 | "version": "1.0.5",
150 | "resolved": "http://r.cnpmjs.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz",
151 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
152 | },
153 | "esutils": {
154 | "version": "2.0.2",
155 | "resolved": "http://r.cnpmjs.org/esutils/download/esutils-2.0.2.tgz",
156 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
157 | },
158 | "globals": {
159 | "version": "11.12.0",
160 | "resolved": "http://r.cnpmjs.org/globals/download/globals-11.12.0.tgz",
161 | "integrity": "sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4="
162 | },
163 | "has-flag": {
164 | "version": "3.0.0",
165 | "resolved": "http://r.cnpmjs.org/has-flag/download/has-flag-3.0.0.tgz",
166 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
167 | },
168 | "js-tokens": {
169 | "version": "4.0.0",
170 | "resolved": "http://r.cnpmjs.org/js-tokens/download/js-tokens-4.0.0.tgz",
171 | "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk="
172 | },
173 | "jsesc": {
174 | "version": "2.5.2",
175 | "resolved": "http://r.cnpmjs.org/jsesc/download/jsesc-2.5.2.tgz",
176 | "integrity": "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q="
177 | },
178 | "lodash": {
179 | "version": "4.17.11",
180 | "resolved": "http://r.cnpmjs.org/lodash/download/lodash-4.17.11.tgz",
181 | "integrity": "sha1-s56mIp72B+zYniyN8SU2iRysm40="
182 | },
183 | "ms": {
184 | "version": "2.1.2",
185 | "resolved": "http://r.cnpmjs.org/ms/download/ms-2.1.2.tgz",
186 | "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
187 | },
188 | "source-map": {
189 | "version": "0.5.7",
190 | "resolved": "http://r.cnpmjs.org/source-map/download/source-map-0.5.7.tgz",
191 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
192 | },
193 | "supports-color": {
194 | "version": "5.5.0",
195 | "resolved": "http://r.cnpmjs.org/supports-color/download/supports-color-5.5.0.tgz",
196 | "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=",
197 | "requires": {
198 | "has-flag": "^3.0.0"
199 | }
200 | },
201 | "tapable": {
202 | "version": "1.1.3",
203 | "resolved": "http://r.cnpmjs.org/tapable/download/tapable-1.1.3.tgz",
204 | "integrity": "sha1-ofzMBrWNth/XpF2i2kT186Pme6I="
205 | },
206 | "to-fast-properties": {
207 | "version": "2.0.0",
208 | "resolved": "http://r.cnpmjs.org/to-fast-properties/download/to-fast-properties-2.0.0.tgz",
209 | "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
210 | },
211 | "trim-right": {
212 | "version": "1.0.1",
213 | "resolved": "http://r.cnpmjs.org/trim-right/download/trim-right-1.0.1.tgz",
214 | "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM="
215 | }
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/chapter3/server/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "accepts": {
8 | "version": "1.3.7",
9 | "resolved": "http://r.cnpmjs.org/accepts/download/accepts-1.3.7.tgz",
10 | "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=",
11 | "requires": {
12 | "mime-types": "~2.1.24",
13 | "negotiator": "0.6.2"
14 | }
15 | },
16 | "array-flatten": {
17 | "version": "1.1.1",
18 | "resolved": "http://r.cnpmjs.org/array-flatten/download/array-flatten-1.1.1.tgz",
19 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
20 | },
21 | "body-parser": {
22 | "version": "1.19.0",
23 | "resolved": "http://r.cnpmjs.org/body-parser/download/body-parser-1.19.0.tgz",
24 | "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=",
25 | "requires": {
26 | "bytes": "3.1.0",
27 | "content-type": "~1.0.4",
28 | "debug": "2.6.9",
29 | "depd": "~1.1.2",
30 | "http-errors": "1.7.2",
31 | "iconv-lite": "0.4.24",
32 | "on-finished": "~2.3.0",
33 | "qs": "6.7.0",
34 | "raw-body": "2.4.0",
35 | "type-is": "~1.6.17"
36 | }
37 | },
38 | "bytes": {
39 | "version": "3.1.0",
40 | "resolved": "http://r.cnpmjs.org/bytes/download/bytes-3.1.0.tgz",
41 | "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY="
42 | },
43 | "content-disposition": {
44 | "version": "0.5.3",
45 | "resolved": "http://r.cnpmjs.org/content-disposition/download/content-disposition-0.5.3.tgz",
46 | "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=",
47 | "requires": {
48 | "safe-buffer": "5.1.2"
49 | }
50 | },
51 | "content-type": {
52 | "version": "1.0.4",
53 | "resolved": "http://r.cnpmjs.org/content-type/download/content-type-1.0.4.tgz",
54 | "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js="
55 | },
56 | "cookie": {
57 | "version": "0.4.0",
58 | "resolved": "http://r.cnpmjs.org/cookie/download/cookie-0.4.0.tgz",
59 | "integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo="
60 | },
61 | "cookie-signature": {
62 | "version": "1.0.6",
63 | "resolved": "http://r.cnpmjs.org/cookie-signature/download/cookie-signature-1.0.6.tgz",
64 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
65 | },
66 | "cors": {
67 | "version": "2.8.5",
68 | "resolved": "http://r.cnpmjs.org/cors/download/cors-2.8.5.tgz",
69 | "integrity": "sha1-6sEdpRWS3Ya58G9uesKTs9+HXSk=",
70 | "requires": {
71 | "object-assign": "^4",
72 | "vary": "^1"
73 | }
74 | },
75 | "debug": {
76 | "version": "2.6.9",
77 | "resolved": "http://r.cnpmjs.org/debug/download/debug-2.6.9.tgz",
78 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
79 | "requires": {
80 | "ms": "2.0.0"
81 | }
82 | },
83 | "depd": {
84 | "version": "1.1.2",
85 | "resolved": "http://r.cnpmjs.org/depd/download/depd-1.1.2.tgz",
86 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
87 | },
88 | "destroy": {
89 | "version": "1.0.4",
90 | "resolved": "http://r.cnpmjs.org/destroy/download/destroy-1.0.4.tgz",
91 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
92 | },
93 | "ee-first": {
94 | "version": "1.1.1",
95 | "resolved": "http://r.cnpmjs.org/ee-first/download/ee-first-1.1.1.tgz",
96 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
97 | },
98 | "encodeurl": {
99 | "version": "1.0.2",
100 | "resolved": "http://r.cnpmjs.org/encodeurl/download/encodeurl-1.0.2.tgz",
101 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
102 | },
103 | "escape-html": {
104 | "version": "1.0.3",
105 | "resolved": "http://r.cnpmjs.org/escape-html/download/escape-html-1.0.3.tgz",
106 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
107 | },
108 | "etag": {
109 | "version": "1.8.1",
110 | "resolved": "http://r.cnpmjs.org/etag/download/etag-1.8.1.tgz",
111 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
112 | },
113 | "express": {
114 | "version": "4.17.0",
115 | "resolved": "http://r.cnpmjs.org/express/download/express-4.17.0.tgz",
116 | "integrity": "sha1-KIr2IiinP0yOopkLo7eRu4fNRDg=",
117 | "requires": {
118 | "accepts": "~1.3.7",
119 | "array-flatten": "1.1.1",
120 | "body-parser": "1.19.0",
121 | "content-disposition": "0.5.3",
122 | "content-type": "~1.0.4",
123 | "cookie": "0.4.0",
124 | "cookie-signature": "1.0.6",
125 | "debug": "2.6.9",
126 | "depd": "~1.1.2",
127 | "encodeurl": "~1.0.2",
128 | "escape-html": "~1.0.3",
129 | "etag": "~1.8.1",
130 | "finalhandler": "~1.1.2",
131 | "fresh": "0.5.2",
132 | "merge-descriptors": "1.0.1",
133 | "methods": "~1.1.2",
134 | "on-finished": "~2.3.0",
135 | "parseurl": "~1.3.3",
136 | "path-to-regexp": "0.1.7",
137 | "proxy-addr": "~2.0.5",
138 | "qs": "6.7.0",
139 | "range-parser": "~1.2.1",
140 | "safe-buffer": "5.1.2",
141 | "send": "0.17.1",
142 | "serve-static": "1.14.1",
143 | "setprototypeof": "1.1.1",
144 | "statuses": "~1.5.0",
145 | "type-is": "~1.6.18",
146 | "utils-merge": "1.0.1",
147 | "vary": "~1.1.2"
148 | }
149 | },
150 | "finalhandler": {
151 | "version": "1.1.2",
152 | "resolved": "http://r.cnpmjs.org/finalhandler/download/finalhandler-1.1.2.tgz",
153 | "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=",
154 | "requires": {
155 | "debug": "2.6.9",
156 | "encodeurl": "~1.0.2",
157 | "escape-html": "~1.0.3",
158 | "on-finished": "~2.3.0",
159 | "parseurl": "~1.3.3",
160 | "statuses": "~1.5.0",
161 | "unpipe": "~1.0.0"
162 | }
163 | },
164 | "forwarded": {
165 | "version": "0.1.2",
166 | "resolved": "http://r.cnpmjs.org/forwarded/download/forwarded-0.1.2.tgz",
167 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
168 | },
169 | "fresh": {
170 | "version": "0.5.2",
171 | "resolved": "http://r.cnpmjs.org/fresh/download/fresh-0.5.2.tgz",
172 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
173 | },
174 | "http-errors": {
175 | "version": "1.7.2",
176 | "resolved": "http://r.cnpmjs.org/http-errors/download/http-errors-1.7.2.tgz",
177 | "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=",
178 | "requires": {
179 | "depd": "~1.1.2",
180 | "inherits": "2.0.3",
181 | "setprototypeof": "1.1.1",
182 | "statuses": ">= 1.5.0 < 2",
183 | "toidentifier": "1.0.0"
184 | }
185 | },
186 | "iconv-lite": {
187 | "version": "0.4.24",
188 | "resolved": "http://r.cnpmjs.org/iconv-lite/download/iconv-lite-0.4.24.tgz",
189 | "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=",
190 | "requires": {
191 | "safer-buffer": ">= 2.1.2 < 3"
192 | }
193 | },
194 | "inherits": {
195 | "version": "2.0.3",
196 | "resolved": "http://r.cnpmjs.org/inherits/download/inherits-2.0.3.tgz",
197 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
198 | },
199 | "ipaddr.js": {
200 | "version": "1.9.0",
201 | "resolved": "http://r.cnpmjs.org/ipaddr.js/download/ipaddr.js-1.9.0.tgz",
202 | "integrity": "sha1-N9905DCg5HVQ/lSi3v4w2KzZX2U="
203 | },
204 | "media-typer": {
205 | "version": "0.3.0",
206 | "resolved": "http://r.cnpmjs.org/media-typer/download/media-typer-0.3.0.tgz",
207 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
208 | },
209 | "merge-descriptors": {
210 | "version": "1.0.1",
211 | "resolved": "http://r.cnpmjs.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz",
212 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
213 | },
214 | "methods": {
215 | "version": "1.1.2",
216 | "resolved": "http://r.cnpmjs.org/methods/download/methods-1.1.2.tgz",
217 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
218 | },
219 | "mime": {
220 | "version": "1.6.0",
221 | "resolved": "http://r.cnpmjs.org/mime/download/mime-1.6.0.tgz",
222 | "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE="
223 | },
224 | "mime-db": {
225 | "version": "1.40.0",
226 | "resolved": "http://r.cnpmjs.org/mime-db/download/mime-db-1.40.0.tgz",
227 | "integrity": "sha1-plBX6ZjbCQ9zKmj2wnbTh9QSbDI="
228 | },
229 | "mime-types": {
230 | "version": "2.1.24",
231 | "resolved": "http://r.cnpmjs.org/mime-types/download/mime-types-2.1.24.tgz",
232 | "integrity": "sha1-tvjQs+lR77d97eyhlM/20W9nb4E=",
233 | "requires": {
234 | "mime-db": "1.40.0"
235 | }
236 | },
237 | "ms": {
238 | "version": "2.0.0",
239 | "resolved": "http://r.cnpmjs.org/ms/download/ms-2.0.0.tgz",
240 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
241 | },
242 | "negotiator": {
243 | "version": "0.6.2",
244 | "resolved": "http://r.cnpmjs.org/negotiator/download/negotiator-0.6.2.tgz",
245 | "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs="
246 | },
247 | "object-assign": {
248 | "version": "4.1.1",
249 | "resolved": "http://r.cnpmjs.org/object-assign/download/object-assign-4.1.1.tgz",
250 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
251 | },
252 | "on-finished": {
253 | "version": "2.3.0",
254 | "resolved": "http://r.cnpmjs.org/on-finished/download/on-finished-2.3.0.tgz",
255 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
256 | "requires": {
257 | "ee-first": "1.1.1"
258 | }
259 | },
260 | "parseurl": {
261 | "version": "1.3.3",
262 | "resolved": "http://r.cnpmjs.org/parseurl/download/parseurl-1.3.3.tgz",
263 | "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ="
264 | },
265 | "path-to-regexp": {
266 | "version": "0.1.7",
267 | "resolved": "http://r.cnpmjs.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz",
268 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
269 | },
270 | "proxy-addr": {
271 | "version": "2.0.5",
272 | "resolved": "http://r.cnpmjs.org/proxy-addr/download/proxy-addr-2.0.5.tgz",
273 | "integrity": "sha1-NMvWSi2B9LH9IedvnwbIpFKZ7jQ=",
274 | "requires": {
275 | "forwarded": "~0.1.2",
276 | "ipaddr.js": "1.9.0"
277 | }
278 | },
279 | "qs": {
280 | "version": "6.7.0",
281 | "resolved": "http://r.cnpmjs.org/qs/download/qs-6.7.0.tgz",
282 | "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw="
283 | },
284 | "range-parser": {
285 | "version": "1.2.1",
286 | "resolved": "http://r.cnpmjs.org/range-parser/download/range-parser-1.2.1.tgz",
287 | "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE="
288 | },
289 | "raw-body": {
290 | "version": "2.4.0",
291 | "resolved": "http://r.cnpmjs.org/raw-body/download/raw-body-2.4.0.tgz",
292 | "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=",
293 | "requires": {
294 | "bytes": "3.1.0",
295 | "http-errors": "1.7.2",
296 | "iconv-lite": "0.4.24",
297 | "unpipe": "1.0.0"
298 | }
299 | },
300 | "safe-buffer": {
301 | "version": "5.1.2",
302 | "resolved": "http://r.cnpmjs.org/safe-buffer/download/safe-buffer-5.1.2.tgz",
303 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0="
304 | },
305 | "safer-buffer": {
306 | "version": "2.1.2",
307 | "resolved": "http://r.cnpmjs.org/safer-buffer/download/safer-buffer-2.1.2.tgz",
308 | "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo="
309 | },
310 | "send": {
311 | "version": "0.17.1",
312 | "resolved": "http://r.cnpmjs.org/send/download/send-0.17.1.tgz",
313 | "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=",
314 | "requires": {
315 | "debug": "2.6.9",
316 | "depd": "~1.1.2",
317 | "destroy": "~1.0.4",
318 | "encodeurl": "~1.0.2",
319 | "escape-html": "~1.0.3",
320 | "etag": "~1.8.1",
321 | "fresh": "0.5.2",
322 | "http-errors": "~1.7.2",
323 | "mime": "1.6.0",
324 | "ms": "2.1.1",
325 | "on-finished": "~2.3.0",
326 | "range-parser": "~1.2.1",
327 | "statuses": "~1.5.0"
328 | },
329 | "dependencies": {
330 | "ms": {
331 | "version": "2.1.1",
332 | "resolved": "http://r.cnpmjs.org/ms/download/ms-2.1.1.tgz",
333 | "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo="
334 | }
335 | }
336 | },
337 | "serve-static": {
338 | "version": "1.14.1",
339 | "resolved": "http://r.cnpmjs.org/serve-static/download/serve-static-1.14.1.tgz",
340 | "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=",
341 | "requires": {
342 | "encodeurl": "~1.0.2",
343 | "escape-html": "~1.0.3",
344 | "parseurl": "~1.3.3",
345 | "send": "0.17.1"
346 | }
347 | },
348 | "setprototypeof": {
349 | "version": "1.1.1",
350 | "resolved": "http://r.cnpmjs.org/setprototypeof/download/setprototypeof-1.1.1.tgz",
351 | "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM="
352 | },
353 | "statuses": {
354 | "version": "1.5.0",
355 | "resolved": "http://r.cnpmjs.org/statuses/download/statuses-1.5.0.tgz",
356 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
357 | },
358 | "toidentifier": {
359 | "version": "1.0.0",
360 | "resolved": "http://r.cnpmjs.org/toidentifier/download/toidentifier-1.0.0.tgz",
361 | "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM="
362 | },
363 | "type-is": {
364 | "version": "1.6.18",
365 | "resolved": "http://r.cnpmjs.org/type-is/download/type-is-1.6.18.tgz",
366 | "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=",
367 | "requires": {
368 | "media-typer": "0.3.0",
369 | "mime-types": "~2.1.24"
370 | }
371 | },
372 | "unpipe": {
373 | "version": "1.0.0",
374 | "resolved": "http://r.cnpmjs.org/unpipe/download/unpipe-1.0.0.tgz",
375 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
376 | },
377 | "utils-merge": {
378 | "version": "1.0.1",
379 | "resolved": "http://r.cnpmjs.org/utils-merge/download/utils-merge-1.0.1.tgz",
380 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
381 | },
382 | "vary": {
383 | "version": "1.1.2",
384 | "resolved": "http://r.cnpmjs.org/vary/download/vary-1.1.2.tgz",
385 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
386 | }
387 | }
388 | }
389 |
--------------------------------------------------------------------------------
/chapter4/webpack-optimize-js/stats.json:
--------------------------------------------------------------------------------
1 | {
2 | "errors": [],
3 | "warnings": [],
4 | "version": "4.30.0",
5 | "hash": "86f2ae7198f0233d2b0c",
6 | "time": 1314,
7 | "builtAt": 1559883892956,
8 | "publicPath": "/",
9 | "outputPath": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\dist\\",
10 | "assetsByChunkName": {
11 | "main": "main.f06b300d.bundle.js"
12 | },
13 | "assets": [
14 | {
15 | "name": "assets\\logo.png",
16 | "size": 8046,
17 | "chunks": [],
18 | "chunkNames": [],
19 | "emitted": true
20 | },
21 | {
22 | "name": "index.html",
23 | "size": 593,
24 | "chunks": [],
25 | "chunkNames": [],
26 | "emitted": true
27 | },
28 | {
29 | "name": "main.f06b300d.bundle.js",
30 | "size": 1363,
31 | "chunks": [
32 | 0
33 | ],
34 | "chunkNames": [
35 | "main"
36 | ],
37 | "emitted": true
38 | },
39 | {
40 | "name": "vue_dll.js",
41 | "size": 146292,
42 | "chunks": [],
43 | "chunkNames": [],
44 | "emitted": true
45 | }
46 | ],
47 | "filteredAssets": 0,
48 | "entrypoints": {
49 | "main": {
50 | "chunks": [
51 | 0
52 | ],
53 | "assets": [
54 | "main.f06b300d.bundle.js"
55 | ],
56 | "children": {},
57 | "childAssets": {}
58 | }
59 | },
60 | "namedChunkGroups": {
61 | "main": {
62 | "chunks": [
63 | 0
64 | ],
65 | "assets": [
66 | "main.f06b300d.bundle.js"
67 | ],
68 | "children": {},
69 | "childAssets": {}
70 | }
71 | },
72 | "chunks": [
73 | {
74 | "id": 0,
75 | "rendered": true,
76 | "initial": true,
77 | "entry": true,
78 | "size": 2062,
79 | "names": [
80 | "main"
81 | ],
82 | "files": [
83 | "main.f06b300d.bundle.js"
84 | ],
85 | "hash": "8e5df0a74971f4330efb",
86 | "siblings": [],
87 | "parents": [],
88 | "children": [],
89 | "childrenByOrder": {},
90 | "modules": [
91 | {
92 | "id": 0,
93 | "identifier": "delegated 2 from dll-reference vue_dll",
94 | "name": "delegated ./node_modules/vue/dist/vue.js from dll-reference vue_dll",
95 | "index": 1,
96 | "index2": 1,
97 | "size": 42,
98 | "built": true,
99 | "optional": false,
100 | "prefetched": false,
101 | "chunks": [
102 | 0
103 | ],
104 | "issuer": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
105 | "issuerId": 3,
106 | "issuerName": "./src/main.js",
107 | "issuerPath": [
108 | {
109 | "id": 3,
110 | "identifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
111 | "name": "./src/main.js",
112 | "profile": {
113 | "factory": 77,
114 | "building": 954
115 | }
116 | }
117 | ],
118 | "profile": {
119 | "factory": 33,
120 | "building": 0,
121 | "dependencies": 1
122 | },
123 | "failed": false,
124 | "errors": 0,
125 | "warnings": 0,
126 | "assets": [],
127 | "reasons": [
128 | {
129 | "moduleId": 3,
130 | "moduleIdentifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
131 | "module": "./src/main.js",
132 | "moduleName": "./src/main.js",
133 | "type": "harmony side effect evaluation",
134 | "userRequest": "vue/dist/vue.js",
135 | "loc": "2:0-34"
136 | },
137 | {
138 | "moduleId": 3,
139 | "moduleIdentifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
140 | "module": "./src/main.js",
141 | "moduleName": "./src/main.js",
142 | "type": "harmony import specifier",
143 | "userRequest": "vue/dist/vue.js",
144 | "loc": "5:0-3"
145 | },
146 | {
147 | "moduleId": 3,
148 | "moduleIdentifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
149 | "module": "./src/main.js",
150 | "moduleName": "./src/main.js",
151 | "type": "harmony import specifier",
152 | "userRequest": "vue/dist/vue.js",
153 | "loc": "21:4-7"
154 | }
155 | ],
156 | "usedExports": true,
157 | "providedExports": null,
158 | "optimizationBailout": [
159 | "ModuleConcatenation bailout: Module is not an ECMAScript module"
160 | ],
161 | "depth": 1
162 | },
163 | {
164 | "id": 1,
165 | "identifier": "delegated 6 from dll-reference vue_dll",
166 | "name": "delegated ./node_modules/vue-router/dist/vue-router.esm.js from dll-reference vue_dll",
167 | "index": 3,
168 | "index2": 2,
169 | "size": 42,
170 | "built": true,
171 | "optional": false,
172 | "prefetched": false,
173 | "chunks": [
174 | 0
175 | ],
176 | "issuer": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
177 | "issuerId": 3,
178 | "issuerName": "./src/main.js",
179 | "issuerPath": [
180 | {
181 | "id": 3,
182 | "identifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
183 | "name": "./src/main.js",
184 | "profile": {
185 | "factory": 77,
186 | "building": 954
187 | }
188 | }
189 | ],
190 | "profile": {
191 | "factory": 33,
192 | "building": 0,
193 | "dependencies": 1
194 | },
195 | "failed": false,
196 | "errors": 0,
197 | "warnings": 0,
198 | "assets": [],
199 | "reasons": [
200 | {
201 | "moduleId": 3,
202 | "moduleIdentifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
203 | "module": "./src/main.js",
204 | "moduleName": "./src/main.js",
205 | "type": "harmony side effect evaluation",
206 | "userRequest": "vue-router",
207 | "loc": "4:0-35"
208 | },
209 | {
210 | "moduleId": 3,
211 | "moduleIdentifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
212 | "module": "./src/main.js",
213 | "moduleName": "./src/main.js",
214 | "type": "harmony import specifier",
215 | "userRequest": "vue-router",
216 | "loc": "5:8-17"
217 | },
218 | {
219 | "moduleId": 3,
220 | "moduleIdentifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
221 | "module": "./src/main.js",
222 | "moduleName": "./src/main.js",
223 | "type": "harmony import specifier",
224 | "userRequest": "vue-router",
225 | "loc": "12:17-26"
226 | }
227 | ],
228 | "usedExports": true,
229 | "providedExports": [
230 | "default"
231 | ],
232 | "optimizationBailout": [
233 | "ModuleConcatenation bailout: Module is not an ECMAScript module"
234 | ],
235 | "depth": 1
236 | },
237 | {
238 | "id": 2,
239 | "identifier": "external \"vue_dll\"",
240 | "name": "external \"vue_dll\"",
241 | "index": 2,
242 | "index2": 0,
243 | "size": 42,
244 | "built": true,
245 | "optional": false,
246 | "prefetched": false,
247 | "chunks": [
248 | 0
249 | ],
250 | "issuer": "delegated 2 from dll-reference vue_dll",
251 | "issuerId": 0,
252 | "issuerName": "delegated ./node_modules/vue/dist/vue.js from dll-reference vue_dll",
253 | "issuerPath": [
254 | {
255 | "id": 3,
256 | "identifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
257 | "name": "./src/main.js",
258 | "profile": {
259 | "factory": 77,
260 | "building": 954
261 | }
262 | },
263 | {
264 | "id": 0,
265 | "identifier": "delegated 2 from dll-reference vue_dll",
266 | "name": "delegated ./node_modules/vue/dist/vue.js from dll-reference vue_dll",
267 | "profile": {
268 | "factory": 33,
269 | "building": 0,
270 | "dependencies": 1
271 | }
272 | }
273 | ],
274 | "profile": {
275 | "factory": 0,
276 | "building": 1
277 | },
278 | "failed": false,
279 | "errors": 0,
280 | "warnings": 0,
281 | "assets": [],
282 | "reasons": [
283 | {
284 | "moduleId": 0,
285 | "moduleIdentifier": "delegated 2 from dll-reference vue_dll",
286 | "module": "delegated ./node_modules/vue/dist/vue.js from dll-reference vue_dll",
287 | "moduleName": "delegated ./node_modules/vue/dist/vue.js from dll-reference vue_dll",
288 | "type": "delegated source",
289 | "userRequest": "dll-reference vue_dll"
290 | },
291 | {
292 | "moduleId": 1,
293 | "moduleIdentifier": "delegated 6 from dll-reference vue_dll",
294 | "module": "delegated ./node_modules/vue-router/dist/vue-router.esm.js from dll-reference vue_dll",
295 | "moduleName": "delegated ./node_modules/vue-router/dist/vue-router.esm.js from dll-reference vue_dll",
296 | "type": "delegated source",
297 | "userRequest": "dll-reference vue_dll"
298 | }
299 | ],
300 | "usedExports": true,
301 | "providedExports": null,
302 | "optimizationBailout": [
303 | "ModuleConcatenation bailout: Module is not an ECMAScript module"
304 | ],
305 | "depth": 2
306 | },
307 | {
308 | "id": 3,
309 | "identifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
310 | "name": "./src/main.js",
311 | "index": 0,
312 | "index2": 3,
313 | "size": 1936,
314 | "cacheable": true,
315 | "built": true,
316 | "optional": false,
317 | "prefetched": false,
318 | "chunks": [
319 | 0
320 | ],
321 | "issuer": null,
322 | "issuerId": null,
323 | "issuerName": null,
324 | "issuerPath": null,
325 | "profile": {
326 | "factory": 77,
327 | "building": 954
328 | },
329 | "failed": false,
330 | "errors": 0,
331 | "warnings": 0,
332 | "assets": [],
333 | "reasons": [
334 | {
335 | "moduleId": null,
336 | "moduleIdentifier": null,
337 | "module": null,
338 | "moduleName": null,
339 | "type": "single entry",
340 | "userRequest": "./src/main.js",
341 | "loc": "main"
342 | }
343 | ],
344 | "usedExports": true,
345 | "providedExports": [],
346 | "optimizationBailout": [
347 | "ModuleConcatenation bailout: Module is an entry point"
348 | ],
349 | "depth": 0,
350 | "source": "// import vue from 'vue' // runtime-only 的 vue 包\nimport Vue from 'vue/dist/vue.js'; // 完整版的vuejs\n\nimport VueRouter from 'vue-router';\nVue.use(VueRouter);\nvar homeComponent = {\n template: '我是homeaaa页面,你好哇!!!黑马程序员!!!!!!嘿嘿嘿!!!哇 好厉害哦!
'\n};\nvar newsComponent = {\n template: '我是newsheiheihei页面
'\n};\nvar router = new VueRouter({\n routes: [{\n path: '/home',\n component: homeComponent\n }, {\n path: '/news',\n component: newsComponent\n }]\n});\nnew Vue({\n el: '#app',\n data: {\n msg: 'helloworld'\n },\n router: router\n}); // import moment from 'moment'\n// // 手动引入语言包\n// import 'moment/locale/zh-cn'\n// // 设置语言\n// moment.locale('zh-CN')\n// console.log(moment().subtract(6, 'days').calendar())\n// 静态导入\n// import $ from 'jquery'\n// import和export必须写在顶级作用域中,否则会报错,因为是静态导入\n// let a = 1\n// if (a = 1) {\n// import $ from 'jquery'\n// } else {\n// import $ from 'webpack'\n// }\n// import 'bootstrap'\n// 需求: 当用户点击按钮时 添加一个div\n// $(function() {\n// $('#btn').click(function() {\n// $('').html('我是main').appendTo('body')\n// })\n// })\n// import a from './a.js'\n// console.log(a.name)\n// window.onload = function() {\n// document.getElementById('btn').onclick = function() {\n// // 当用户点击按钮时才会执行\n// $('').html('我是main').appendTo('body')\n// }\n// }\n// import('jquery') 其实返回的就是一个promise对象\n// function getComponent() {\n// return import('jquery').then(({ default: $ }) => {\n// // 执行resolve时就表示jQuery导入完成了\n// return $('').html('我是main')\n// })\n// }\n// getComponent().then(item => {\n// item.appendTo('body')\n// })\n// window.onload = function () {\n// document.getElementById('btn').onclick = function () {\n// // 当用户点击按钮时才会执行\n// getComponent().then(item => {\n// item.appendTo('body')\n// })\n// }\n// }\n// 动态导入\n// function getComponent() {\n// return import('jquery').then(({ default: $ }) => {\n// return $('').html('我是main')\n// })\n// }"
351 | }
352 | ],
353 | "filteredModules": 0,
354 | "origins": [
355 | {
356 | "module": "",
357 | "moduleIdentifier": "",
358 | "moduleName": "",
359 | "loc": "main",
360 | "request": "./src/main.js",
361 | "reasons": []
362 | }
363 | ]
364 | }
365 | ],
366 | "modules": [
367 | {
368 | "id": 0,
369 | "identifier": "delegated 2 from dll-reference vue_dll",
370 | "name": "delegated ./node_modules/vue/dist/vue.js from dll-reference vue_dll",
371 | "index": 1,
372 | "index2": 1,
373 | "size": 42,
374 | "built": true,
375 | "optional": false,
376 | "prefetched": false,
377 | "chunks": [
378 | 0
379 | ],
380 | "issuer": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
381 | "issuerId": 3,
382 | "issuerName": "./src/main.js",
383 | "issuerPath": [
384 | {
385 | "id": 3,
386 | "identifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
387 | "name": "./src/main.js",
388 | "profile": {
389 | "factory": 77,
390 | "building": 954
391 | }
392 | }
393 | ],
394 | "profile": {
395 | "factory": 33,
396 | "building": 0,
397 | "dependencies": 1
398 | },
399 | "failed": false,
400 | "errors": 0,
401 | "warnings": 0,
402 | "assets": [],
403 | "reasons": [
404 | {
405 | "moduleId": 3,
406 | "moduleIdentifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
407 | "module": "./src/main.js",
408 | "moduleName": "./src/main.js",
409 | "type": "harmony side effect evaluation",
410 | "userRequest": "vue/dist/vue.js",
411 | "loc": "2:0-34"
412 | },
413 | {
414 | "moduleId": 3,
415 | "moduleIdentifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
416 | "module": "./src/main.js",
417 | "moduleName": "./src/main.js",
418 | "type": "harmony import specifier",
419 | "userRequest": "vue/dist/vue.js",
420 | "loc": "5:0-3"
421 | },
422 | {
423 | "moduleId": 3,
424 | "moduleIdentifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
425 | "module": "./src/main.js",
426 | "moduleName": "./src/main.js",
427 | "type": "harmony import specifier",
428 | "userRequest": "vue/dist/vue.js",
429 | "loc": "21:4-7"
430 | }
431 | ],
432 | "usedExports": true,
433 | "providedExports": null,
434 | "optimizationBailout": [
435 | "ModuleConcatenation bailout: Module is not an ECMAScript module"
436 | ],
437 | "depth": 1
438 | },
439 | {
440 | "id": 1,
441 | "identifier": "delegated 6 from dll-reference vue_dll",
442 | "name": "delegated ./node_modules/vue-router/dist/vue-router.esm.js from dll-reference vue_dll",
443 | "index": 3,
444 | "index2": 2,
445 | "size": 42,
446 | "built": true,
447 | "optional": false,
448 | "prefetched": false,
449 | "chunks": [
450 | 0
451 | ],
452 | "issuer": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
453 | "issuerId": 3,
454 | "issuerName": "./src/main.js",
455 | "issuerPath": [
456 | {
457 | "id": 3,
458 | "identifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
459 | "name": "./src/main.js",
460 | "profile": {
461 | "factory": 77,
462 | "building": 954
463 | }
464 | }
465 | ],
466 | "profile": {
467 | "factory": 33,
468 | "building": 0,
469 | "dependencies": 1
470 | },
471 | "failed": false,
472 | "errors": 0,
473 | "warnings": 0,
474 | "assets": [],
475 | "reasons": [
476 | {
477 | "moduleId": 3,
478 | "moduleIdentifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
479 | "module": "./src/main.js",
480 | "moduleName": "./src/main.js",
481 | "type": "harmony side effect evaluation",
482 | "userRequest": "vue-router",
483 | "loc": "4:0-35"
484 | },
485 | {
486 | "moduleId": 3,
487 | "moduleIdentifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
488 | "module": "./src/main.js",
489 | "moduleName": "./src/main.js",
490 | "type": "harmony import specifier",
491 | "userRequest": "vue-router",
492 | "loc": "5:8-17"
493 | },
494 | {
495 | "moduleId": 3,
496 | "moduleIdentifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
497 | "module": "./src/main.js",
498 | "moduleName": "./src/main.js",
499 | "type": "harmony import specifier",
500 | "userRequest": "vue-router",
501 | "loc": "12:17-26"
502 | }
503 | ],
504 | "usedExports": true,
505 | "providedExports": [
506 | "default"
507 | ],
508 | "optimizationBailout": [
509 | "ModuleConcatenation bailout: Module is not an ECMAScript module"
510 | ],
511 | "depth": 1
512 | },
513 | {
514 | "id": 2,
515 | "identifier": "external \"vue_dll\"",
516 | "name": "external \"vue_dll\"",
517 | "index": 2,
518 | "index2": 0,
519 | "size": 42,
520 | "built": true,
521 | "optional": false,
522 | "prefetched": false,
523 | "chunks": [
524 | 0
525 | ],
526 | "issuer": "delegated 2 from dll-reference vue_dll",
527 | "issuerId": 0,
528 | "issuerName": "delegated ./node_modules/vue/dist/vue.js from dll-reference vue_dll",
529 | "issuerPath": [
530 | {
531 | "id": 3,
532 | "identifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
533 | "name": "./src/main.js",
534 | "profile": {
535 | "factory": 77,
536 | "building": 954
537 | }
538 | },
539 | {
540 | "id": 0,
541 | "identifier": "delegated 2 from dll-reference vue_dll",
542 | "name": "delegated ./node_modules/vue/dist/vue.js from dll-reference vue_dll",
543 | "profile": {
544 | "factory": 33,
545 | "building": 0,
546 | "dependencies": 1
547 | }
548 | }
549 | ],
550 | "profile": {
551 | "factory": 0,
552 | "building": 1
553 | },
554 | "failed": false,
555 | "errors": 0,
556 | "warnings": 0,
557 | "assets": [],
558 | "reasons": [
559 | {
560 | "moduleId": 0,
561 | "moduleIdentifier": "delegated 2 from dll-reference vue_dll",
562 | "module": "delegated ./node_modules/vue/dist/vue.js from dll-reference vue_dll",
563 | "moduleName": "delegated ./node_modules/vue/dist/vue.js from dll-reference vue_dll",
564 | "type": "delegated source",
565 | "userRequest": "dll-reference vue_dll"
566 | },
567 | {
568 | "moduleId": 1,
569 | "moduleIdentifier": "delegated 6 from dll-reference vue_dll",
570 | "module": "delegated ./node_modules/vue-router/dist/vue-router.esm.js from dll-reference vue_dll",
571 | "moduleName": "delegated ./node_modules/vue-router/dist/vue-router.esm.js from dll-reference vue_dll",
572 | "type": "delegated source",
573 | "userRequest": "dll-reference vue_dll"
574 | }
575 | ],
576 | "usedExports": true,
577 | "providedExports": null,
578 | "optimizationBailout": [
579 | "ModuleConcatenation bailout: Module is not an ECMAScript module"
580 | ],
581 | "depth": 2
582 | },
583 | {
584 | "id": 3,
585 | "identifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\babel-loader\\lib\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\main.js",
586 | "name": "./src/main.js",
587 | "index": 0,
588 | "index2": 3,
589 | "size": 1936,
590 | "cacheable": true,
591 | "built": true,
592 | "optional": false,
593 | "prefetched": false,
594 | "chunks": [
595 | 0
596 | ],
597 | "issuer": null,
598 | "issuerId": null,
599 | "issuerName": null,
600 | "issuerPath": null,
601 | "profile": {
602 | "factory": 77,
603 | "building": 954
604 | },
605 | "failed": false,
606 | "errors": 0,
607 | "warnings": 0,
608 | "assets": [],
609 | "reasons": [
610 | {
611 | "moduleId": null,
612 | "moduleIdentifier": null,
613 | "module": null,
614 | "moduleName": null,
615 | "type": "single entry",
616 | "userRequest": "./src/main.js",
617 | "loc": "main"
618 | }
619 | ],
620 | "usedExports": true,
621 | "providedExports": [],
622 | "optimizationBailout": [
623 | "ModuleConcatenation bailout: Module is an entry point"
624 | ],
625 | "depth": 0,
626 | "source": "// import vue from 'vue' // runtime-only 的 vue 包\nimport Vue from 'vue/dist/vue.js'; // 完整版的vuejs\n\nimport VueRouter from 'vue-router';\nVue.use(VueRouter);\nvar homeComponent = {\n template: '我是homeaaa页面,你好哇!!!黑马程序员!!!!!!嘿嘿嘿!!!哇 好厉害哦!
'\n};\nvar newsComponent = {\n template: '我是newsheiheihei页面
'\n};\nvar router = new VueRouter({\n routes: [{\n path: '/home',\n component: homeComponent\n }, {\n path: '/news',\n component: newsComponent\n }]\n});\nnew Vue({\n el: '#app',\n data: {\n msg: 'helloworld'\n },\n router: router\n}); // import moment from 'moment'\n// // 手动引入语言包\n// import 'moment/locale/zh-cn'\n// // 设置语言\n// moment.locale('zh-CN')\n// console.log(moment().subtract(6, 'days').calendar())\n// 静态导入\n// import $ from 'jquery'\n// import和export必须写在顶级作用域中,否则会报错,因为是静态导入\n// let a = 1\n// if (a = 1) {\n// import $ from 'jquery'\n// } else {\n// import $ from 'webpack'\n// }\n// import 'bootstrap'\n// 需求: 当用户点击按钮时 添加一个div\n// $(function() {\n// $('#btn').click(function() {\n// $('').html('我是main').appendTo('body')\n// })\n// })\n// import a from './a.js'\n// console.log(a.name)\n// window.onload = function() {\n// document.getElementById('btn').onclick = function() {\n// // 当用户点击按钮时才会执行\n// $('').html('我是main').appendTo('body')\n// }\n// }\n// import('jquery') 其实返回的就是一个promise对象\n// function getComponent() {\n// return import('jquery').then(({ default: $ }) => {\n// // 执行resolve时就表示jQuery导入完成了\n// return $('').html('我是main')\n// })\n// }\n// getComponent().then(item => {\n// item.appendTo('body')\n// })\n// window.onload = function () {\n// document.getElementById('btn').onclick = function () {\n// // 当用户点击按钮时才会执行\n// getComponent().then(item => {\n// item.appendTo('body')\n// })\n// }\n// }\n// 动态导入\n// function getComponent() {\n// return import('jquery').then(({ default: $ }) => {\n// return $('').html('我是main')\n// })\n// }"
627 | }
628 | ],
629 | "filteredModules": 0,
630 | "children": [
631 | {
632 | "errors": [],
633 | "warnings": [],
634 | "publicPath": "/",
635 | "outputPath": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\dist\\",
636 | "assetsByChunkName": {},
637 | "assets": [
638 | {
639 | "name": "index.html",
640 | "size": 4238,
641 | "chunks": [
642 | 0
643 | ],
644 | "chunkNames": [],
645 | "emitted": false
646 | }
647 | ],
648 | "filteredAssets": 0,
649 | "entrypoints": {
650 | "undefined": {
651 | "chunks": [
652 | 0
653 | ],
654 | "assets": [
655 | "index.html"
656 | ],
657 | "children": {},
658 | "childAssets": {}
659 | }
660 | },
661 | "namedChunkGroups": {
662 | "undefined": {
663 | "chunks": [
664 | 0
665 | ],
666 | "assets": [
667 | "index.html"
668 | ],
669 | "children": {},
670 | "childAssets": {}
671 | }
672 | },
673 | "chunks": [
674 | {
675 | "id": 0,
676 | "rendered": true,
677 | "initial": true,
678 | "entry": true,
679 | "size": 522,
680 | "names": [],
681 | "files": [
682 | "index.html"
683 | ],
684 | "hash": "19793510db99382818c1",
685 | "siblings": [],
686 | "parents": [],
687 | "children": [],
688 | "childrenByOrder": {},
689 | "modules": [
690 | {
691 | "id": 0,
692 | "identifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\html-webpack-plugin\\lib\\loader.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\html-withimg-loader\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\index.html",
693 | "name": "./node_modules/html-webpack-plugin/lib/loader.js!./src/index.html",
694 | "index": 0,
695 | "index2": 0,
696 | "size": 522,
697 | "cacheable": true,
698 | "built": true,
699 | "optional": false,
700 | "prefetched": false,
701 | "chunks": [
702 | 0
703 | ],
704 | "issuer": null,
705 | "issuerId": null,
706 | "issuerName": null,
707 | "issuerPath": null,
708 | "profile": {
709 | "factory": 43,
710 | "building": 119
711 | },
712 | "failed": false,
713 | "errors": 0,
714 | "warnings": 0,
715 | "assets": [],
716 | "reasons": [
717 | {
718 | "moduleId": null,
719 | "moduleIdentifier": null,
720 | "module": null,
721 | "moduleName": null,
722 | "type": "single entry",
723 | "userRequest": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\html-webpack-plugin\\lib\\loader.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\index.html"
724 | }
725 | ],
726 | "usedExports": true,
727 | "providedExports": null,
728 | "optimizationBailout": [
729 | "ModuleConcatenation bailout: Module is not an ECMAScript module"
730 | ],
731 | "depth": 0,
732 | "source": "module.exports = \"\\r\\r\\r \\r \\r \\r Document\\r\\r\\r \\r
\\r 去首页\\r 去新闻\\r \\r \\r \\r\\r\""
733 | }
734 | ],
735 | "filteredModules": 0,
736 | "origins": [
737 | {
738 | "module": "",
739 | "moduleIdentifier": "",
740 | "moduleName": "",
741 | "loc": "",
742 | "request": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\html-webpack-plugin\\lib\\loader.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\index.html",
743 | "reasons": []
744 | }
745 | ]
746 | }
747 | ],
748 | "modules": [
749 | {
750 | "id": 0,
751 | "identifier": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\html-webpack-plugin\\lib\\loader.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\html-withimg-loader\\index.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\index.html",
752 | "name": "./node_modules/html-webpack-plugin/lib/loader.js!./src/index.html",
753 | "index": 0,
754 | "index2": 0,
755 | "size": 522,
756 | "cacheable": true,
757 | "built": true,
758 | "optional": false,
759 | "prefetched": false,
760 | "chunks": [
761 | 0
762 | ],
763 | "issuer": null,
764 | "issuerId": null,
765 | "issuerName": null,
766 | "issuerPath": null,
767 | "profile": {
768 | "factory": 43,
769 | "building": 119
770 | },
771 | "failed": false,
772 | "errors": 0,
773 | "warnings": 0,
774 | "assets": [],
775 | "reasons": [
776 | {
777 | "moduleId": null,
778 | "moduleIdentifier": null,
779 | "module": null,
780 | "moduleName": null,
781 | "type": "single entry",
782 | "userRequest": "C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\node_modules\\html-webpack-plugin\\lib\\loader.js!C:\\Users\\itheima\\Desktop\\1-11\\resource\\chapter4\\webpack-optimize-js\\src\\index.html"
783 | }
784 | ],
785 | "usedExports": true,
786 | "providedExports": null,
787 | "optimizationBailout": [
788 | "ModuleConcatenation bailout: Module is not an ECMAScript module"
789 | ],
790 | "depth": 0,
791 | "source": "module.exports = \"\\r\\r\\r \\r \\r \\r Document\\r\\r\\r \\r
\\r 去首页\\r 去新闻\\r \\r \\r \\r\\r\""
792 | }
793 | ],
794 | "filteredModules": 0,
795 | "children": [],
796 | "name": "html-webpack-plugin for \"index.html\""
797 | }
798 | ]
799 | }
800 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # webpack从入门到进阶
2 |
3 | # 第1章 课程介绍
4 |
5 | ## 学什么
6 |
7 | - [webpack官网](https://www.webpackjs.com)
8 |
9 | > 本质上,*webpack* 是一个现代 JavaScript 应用程序的*静态模块打包器(module bundler)*。当 webpack 处理应用程序时,它会递归地构建一个*依赖关系图(dependency graph)*,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 *bundle*。
10 |
11 | 
12 |
13 | - 代码转译
14 | - 模块合并
15 | - 混淆压缩
16 | - 代码分割
17 | - 自动刷新
18 | - 代码校验
19 | - 自动部署
20 |
21 | ## 课程安排
22 |
23 | - webpack基础配置
24 | - webpack高级配置
25 | - webpack性能优化
26 | - tapable钩子
27 | - AST抽象语法树的应用
28 | - webpack原理分析, 手写webpack
29 | - 手写常见的loader和plugin
30 |
31 | ## 学习前提
32 |
33 | - JS基础
34 | - ES6 / ES7 语法
35 | - node基础
36 | - npm的基本使用
37 |
38 | ## 课程目标
39 |
40 | - 掌握webpack的安装
41 | - 掌握webpack的基础配置
42 | - 掌握loader的配置
43 | - 掌握plugin的配置
44 | - 了解webpack性能优化
45 | - 了解webpack中的tapable
46 | - 了解AST的应用
47 | - 深入学习webpack原理,手写webpack
48 |
49 | # 第2章 webpack基础
50 |
51 | ## webpack的安装
52 |
53 | 注意:请先自行安装[nodejs](https://nodejs.org)最新版的环境
54 |
55 | - 全局安装webpack
56 |
57 | `npm i webpack webpack-cli -g`
58 |
59 | - 项目中安装webpack (推荐)
60 |
61 | `npm i webpack webpack-cli -D`
62 |
63 | ## webpack的使用
64 |
65 | ### webpack-cli
66 |
67 | npm 5.2 以上的版本中提供了一个`npx`命令
68 |
69 | npx 想要解决的主要问题,就是调用项目内部安装的模块,原理就是在`node_modules`下的`.bin` 目录中找到对应的命令执行
70 |
71 | 使用webpack命令:`npx webpack`
72 |
73 | webpack4.0之后可以实现0配置打包构建,0配置的特点就是限制较多,无法自定义很多配置
74 |
75 | 开发中常用的还是使用webpack配置进行打包构建
76 |
77 | ### webpack配置
78 |
79 | webpack有四大核心概念:
80 |
81 | - 入口(entry): 程序的入口js
82 | - 输出(output): 打包后存放的位置
83 | - loader: 用于对模块的源代码进行转换
84 | - 插件(plugins): 插件目的在于解决 loader无法实现的**其他事**
85 |
86 | 1. 配置webpack.config.js
87 | 2. 运行`npx webpack`
88 |
89 | ```js
90 | const path = require('path')
91 |
92 | module.exports = {
93 | // 入口文件配置
94 | entry: './src/index.js',
95 | // 出口文件配置项
96 | output: {
97 | // 输出的路径,webpack2起就规定必须是绝对路径
98 | path: path.join(__dirname, 'dist'),
99 | // 输出文件名字
100 | filename: 'bundle.js'
101 | },
102 | mode: 'development' // 默认为production, 可以手动设置为development, 区别就是是否进行压缩混淆
103 | }
104 | ```
105 |
106 | 将`npx webpack`命令配置到`package.json`的脚本中
107 |
108 | 1. 配置`package.json`
109 | 2. 运行`npm run build`
110 |
111 | ```json
112 | {
113 | "name": "webpack-basic",
114 | "version": "1.0.0",
115 | "main": "index.js",
116 | "license": "MIT",
117 | "scripts": {
118 | "build": "webpack"
119 | },
120 | "devDependencies": {
121 | "webpack": "^4.30.0",
122 | "webpack-cli": "^3.3.1"
123 | }
124 | }
125 | ```
126 |
127 | ### 开发时自动编译工具
128 |
129 | 每次要编译代码时,手动运行 `npm run build` 就会变得很麻烦。
130 |
131 | webpack 中有几个不同的选项,可以帮助你在代码发生变化后自动编译代码:
132 |
133 | 1. webpack's Watch Mode
134 | 2. webpack-dev-server
135 | 3. webpack-dev-middleware
136 |
137 | 多数场景中,可能需要使用 `webpack-dev-server`,但是不妨探讨一下以上的所有选项。
138 |
139 | #### watch
140 |
141 | 在`webpack`指令后面加上`--watch`参数即可
142 |
143 | 主要的作用就是监视本地项目文件的变化, 发现有修改的代码会自动编译打包, 生成输出文件
144 |
145 | 1. 配置`package.json`的scripts`"watch": "webpack --watch"`
146 |
147 | 2. 运行`npm run watch`
148 |
149 | 以上是cli的方式设置watch的参数
150 |
151 | 还可以通过配置文件对watch的参数进行修改:
152 |
153 | ```js
154 | const path = require('path')
155 |
156 | // webpack的配置文件遵循着CommonJS规范
157 | module.exports = {
158 | entry: './src/main.js',
159 | output: {
160 | // path.resolve() : 解析当前相对路径的绝对路径
161 | // path: path.resolve('./dist/'),
162 | // path: path.resolve(__dirname, './dist/'),
163 | path: path.join(__dirname, './dist/'),
164 | filename: 'bundle.js'
165 | },
166 | mode: 'development',
167 | watch: true
168 | }
169 | ```
170 |
171 | 运行`npm run build`
172 |
173 | #### webpack-dev-server (推荐)
174 |
175 | 1. 安装`devServer`:
176 |
177 | `devServer`需要依赖`webpack`,必须在项目依赖中安装`webpack`
178 |
179 | `npm i webpack-dev-server webpack -D`
180 |
181 | 2. index.html中修改 ``
182 |
183 | 3. 运行:`npx webpack-dev-server`
184 |
185 | 4. 运行:`npx webpack-dev-server --hot --open --port 8090`
186 |
187 | 5. 配置`package.json`的scripts:`"dev": "webpack-dev-server --hot --open --port 8090"`
188 |
189 | 6. 运行`npm run dev`
190 |
191 | devServer会在内存中生成一个打包好的`bundle.js`,专供开发时使用,打包效率高,修改代码后会自动重新打包以及刷新浏览器,用户体验非常好
192 |
193 | 以上是cli的方式设置devServer的参数
194 |
195 | 还可以通过配置文件对devServer的参数进行修改:
196 |
197 | 1. 修改`webpack.config.js`
198 |
199 | ```js
200 | const path = require('path')
201 |
202 | module.exports = {
203 | // 入口文件配置
204 | entry: './src/index.js',
205 | // 出口文件配置项
206 | output: {
207 | // 输出的路径,webpack2起就规定必须是绝对路径
208 | path: path.join(__dirname, 'dist'),
209 | // 输出文件名字
210 | filename: 'bundle.js'
211 | },
212 | devServer: {
213 | port: 8090,
214 | open: true,
215 | hot: true
216 | },
217 | mode: 'development'
218 | }
219 | ```
220 |
221 | 2. 修改package.json的scripts: `"dev": "webpack-dev-server"`
222 | 3. 运行`npm run dev`
223 |
224 | #### html插件
225 |
226 | 1. 安装html-webpack-plugin插件`npm i html-webpack-plugin -D`
227 | 2. 在`webpack.config.js`中的`plugins`节点下配置
228 |
229 | ```js
230 | const HtmlWebpackPlugin = require('html-webpack-plugin')
231 |
232 | plugins: [
233 | new HtmlWebpackPlugin({
234 | filename: 'index.html',
235 | template: 'template.html'
236 | })
237 | ]
238 | ```
239 |
240 | 1. devServer时根据模板在express项目根目录下生成html文件(类似于devServer生成内存中的bundle.js)
241 | 2. devServer时自动引入bundle.js
242 | 3. 打包时会自动生成index.html
243 |
244 | #### webpack-dev-middleware
245 |
246 | `webpack-dev-middleware` 是一个容器(wrapper),它可以把 webpack 处理后的文件传递给一个服务器(server)。 `webpack-dev-server` 在内部使用了它,同时,它也可以作为一个单独的包来使用,以便进行更多自定义设置来实现更多的需求。
247 |
248 | 1. 安装 `express` 和 `webpack-dev-middleware`:
249 |
250 | `npm i express webpack-dev-middleware -D`
251 |
252 | 2. 新建`server.js`
253 |
254 | ```js
255 | const express = require('express');
256 | const webpack = require('webpack');
257 | const webpackDevMiddleware = require('webpack-dev-middleware');
258 | const config = require('./webpack.config.js');
259 |
260 | const app = express();
261 | const compiler = webpack(config);
262 |
263 | app.use(webpackDevMiddleware(compiler, {
264 | publicPath: '/'
265 | }));
266 |
267 | app.listen(3000, function () {
268 | console.log('http://localhost:3000');
269 | });
270 | ```
271 |
272 | 3. 配置`package.json`中的scripts:`"server": "node server.js"`
273 |
274 | 4. 运行: `npm run server`
275 |
276 | 注意: 如果要使用`webpack-dev-middleware`, 必须使用`html-webpack-plugin`插件, 否则html文件无法正确的输出到express服务器的根目录
277 |
278 | #### 小结
279 |
280 | 只有在开发时才需要使用自动编译工具, 例如: webpack-dev-server
281 |
282 | 项目上线时都会直接使用webpack进行打包构建, 不需要使用这些自动编译工具
283 |
284 | 自动编译工具只是为了**提高开发体验**
285 |
286 | ### 处理css
287 |
288 | 1. 安装`npm i css-loader style-loader -D`
289 | 2. 配置`webpack.config.js`
290 |
291 | ```js
292 | module: {
293 | rules: [
294 | // 配置的是用来解析.css文件的loader(style-loader和css-loader)
295 | {
296 | // 用正则匹配当前访问的文件的后缀名是 .css
297 | test: /\.css$/,
298 | use: ['style-loader', 'css-loader'] // webpack底层调用这些包的顺序是从右到左
299 | }
300 | ]
301 | }
302 | ```
303 |
304 | loader的释义:
305 |
306 | 1. css-loader: 解析css文件
307 | 2. style-loader: 将解析出来的结果 放到html中, 使其生效
308 |
309 | ### 处理less 和 sass
310 |
311 | `npm i less less-loader sass-loader node-sass -D`
312 |
313 | ```js
314 | { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
315 | ```
316 |
317 | ```js
318 | { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }
319 | ```
320 |
321 | ### 处理图片和字体
322 |
323 | 1. `npm i file-loader url-loader -D`
324 |
325 | url-loader封装了file-loader, 所以使用url-loader时需要安装file-loader
326 |
327 | ```js
328 | {
329 | test: /\.(png|jpg|gif)/,
330 | use: [{
331 | loader: 'url-loader',
332 | options: {
333 | // limit表示如果图片大于5KB,就以路径形式展示,小于的话就用base64格式展示
334 | limit: 5 * 1024,
335 | // 打包输出目录
336 | outputPath: 'images',
337 | // 打包输出图片名称
338 | name: '[name]-[hash:4].[ext]'
339 | }
340 | }]
341 | }
342 | ```
343 |
344 | ### babel
345 |
346 | 1. `npm i babel-loader @babel/core @babel/preset-env webpack -D`
347 |
348 | 2. 如果需要支持更高级的ES6语法, 可以继续安装插件:
349 |
350 | `npm i @babel/plugin-proposal-class-properties -D`
351 |
352 | 也可以根据需要在babel官网找插件进行安装
353 |
354 | ```js
355 | {
356 | test: /\.js$/,
357 | use: {
358 | loader: 'babel-loader',
359 | options: {
360 | presets: ['@babel/env'],
361 | plugins: ['@babel/plugin-proposal-class-properties']
362 | }
363 | },
364 | exclude: /node_modules/
365 | }
366 | ```
367 |
368 | 官方更建议的做法是在项目根目录下新建一个`.babelrc`的babel配置文件
369 |
370 | ```json
371 | {
372 | "presets": ["@babel/env"],
373 | "plugins": ["@babel/plugin-proposal-class-properties"]
374 | }
375 | ```
376 |
377 | 如果需要使用`generator`,无法直接使用babel进行转换,因为会将`generator`转换为一个`regeneratorRuntime`,然后使用`mark`和`wrap`来实现`generator`
378 |
379 | 但由于babel并没有内置`regeneratorRuntime`,所以无法直接使用
380 |
381 | 需要安装插件:
382 |
383 | `npm i @babel/plugin-transform-runtime -D`
384 |
385 | 同时还需安装运行时依赖:
386 |
387 | `npm i @babel/runtime -D`
388 |
389 | 在`.babelrc`中添加插件:
390 |
391 | ```json
392 | {
393 | "presets": [
394 | "@babel/env"
395 | ],
396 | "plugins": [
397 | "@babel/plugin-proposal-class-properties",
398 | "@babel/plugin-transform-runtime"
399 | ]
400 | }
401 | ```
402 |
403 | 如果需要使用ES6/7中对象原型提供的新方法,babel默认情况无法转换,即使用了`transform-runtime`的插件也不支持转换原型上的方法
404 |
405 | 需要使用另一个模块:
406 |
407 | `npm i @babel/polyfill -S`
408 |
409 | 该模块需要在使用新方法的地方直接引入:
410 |
411 | `import '@babel/polyfill'`
412 |
413 | ### source map的使用
414 |
415 | #### devtool
416 |
417 | 此选项控制是否生成,以及如何生成 source map。
418 |
419 | 使用 [`SourceMapDevToolPlugin`](https://www.webpackjs.com/plugins/source-map-dev-tool-plugin) 进行更细粒度的配置。查看 [`source-map-loader`](https://www.webpackjs.com/loaders/source-map-loader) 来处理已有的 source map。
420 |
421 | 选择一种 [source map](http://blog.teamtreehouse.com/introduction-source-maps) 格式来增强调试过程。不同的值会明显影响到构建(build)和重新构建(rebuild)的速度。
422 |
423 | > 可以直接使用 `SourceMapDevToolPlugin`/`EvalSourceMapDevToolPlugin` 来替代使用 `devtool` 选项,它有更多的选项,但是切勿同时使用 `devtool` 选项和 `SourceMapDevToolPlugin`/`EvalSourceMapDevToolPlugin` 插件。因为`devtool` 选项在内部添加过这些插件,所以会应用两次插件。
424 |
425 | | devtool | 构建速度 | 重新构建速度 | 生产环境 | 品质(quality) |
426 | | ------- | -------- | ------------ | -------- | ------------- |
427 | | (none) | +++ | +++ | yes | 打包后的代码 |
428 | | eval | +++ | +++ | no | 生成后的代码 |
429 | | cheap-eval-source-map |+ | ++ | no | 转换过的代码(仅限行) |
430 | | cheap-module-eval-source-map | o |++ | no | 原始源代码(仅限行) |
431 | | eval-source-map | -- | + | no | 原始源代码 |
432 | | cheap-source-map | + | o |no | 转换过的代码(仅限行) |
433 | | cheap-module-source-map | o | - | no | 原始源代码(仅限行) |
434 | | inline-cheap-source-map | + | o | no | 转换过的代码(仅限行) |
435 | | inline-cheap-module-source-map | o | - | no | 原始源代码(仅限行) |
436 | |source-map | -- | -- | yes | 原始源代码 |
437 | | inline-source-map | -- | -- | no | 原始源代码 |
438 | | hidden-source-map | -- | -- | yes | 原始源代码 |
439 | | nosources-source-map | -- | -- | yes | 无源代码内容 |
440 |
441 | #### 这么多模式用哪个好?
442 |
443 | 开发环境推荐:
444 |
445 | **cheap-module-eval-source-map**
446 |
447 | 生产环境推荐:
448 |
449 | **none(不使用source map)**
450 |
451 | 原因如下:
452 |
453 | 1. **使用 cheap 模式可以大幅提高 soure map 生成的效率。**大部分情况我们调试并不关心列信息,而且就算 source map 没有列,有些浏览器引擎(例如 v8) 也会给出列信息。
454 | 2. **使用 module 可支持 babel 这种预编译工具,映射转换前的代码**。
455 | 3. **使用 eval 方式可大幅提高持续构建效率。**官方文档提供的速度对比表格可以看到 eval 模式的重新构建速度都很快。
456 | 4. **使用 eval-source-map 模式可以减少网络请求。**这种模式开启 DataUrl 本身包含完整 sourcemap 信息,并不需要像 sourceURL 那样,浏览器需要发送一个完整请求去获取 sourcemap 文件,这会略微提高点效率。而生产环境中则不宜用 eval,这样会让文件变得极大。
457 |
458 | ### 插件
459 |
460 | #### clean-webpack-plugin
461 |
462 | 该插件在`npm run build`时自动清除`dist`目录后重新生成,非常方便
463 |
464 | 1. 安装插件
465 |
466 | `npm i clean-webpack-plugin -D`
467 |
468 | 2. 引入插件
469 |
470 | ```js
471 | const CleanWebpackPlugin = require('clean-webpack-plugin')
472 | ```
473 |
474 | 3. 使用插件, 在plugins中直接创建对象即可
475 |
476 | ```js
477 | plugins: [
478 | new HtmlWebpackPlugin({
479 | filename: 'index.html',
480 | template: './src/index.html'
481 | }),
482 | new CleanWebpackPlugin()
483 | ],
484 | ```
485 |
486 | #### copy-webpack-plugin
487 |
488 | 1. 安装插件
489 |
490 | `npm i copy-webpack-plugin -D`
491 |
492 | 2. 引入插件
493 |
494 | ```js
495 | const CopyWebpackPlugin = require('copy-webpack-plugin')
496 | ```
497 |
498 | 3. 使用插件, 在plugins中插件对象并配置源和目标
499 |
500 | from: 源, 从哪里拷贝, 可以是相对路径或绝对路径, 推荐绝对路径
501 |
502 | to: 目标, 拷贝到哪里去, 相对于`output`的路径, 同样可以相对路径或绝对路径, 但更推荐相对路径(直接算相对dist目录即可)
503 |
504 | ```js
505 | plugins: [
506 | new HtmlWebpackPlugin({
507 | filename: 'index.html',
508 | template: './src/index.html'
509 | }),
510 | new CleanWebpackPlugin(),
511 | new CopyWebpackPlugin([
512 | {
513 | from: path.join(__dirname, 'assets'),
514 | to: 'assets'
515 | }
516 | ])
517 | ],
518 | ```
519 |
520 | #### BannerPlugin
521 |
522 | 这是一个webpack的内置插件,用于给打包的JS文件加上版权注释信息
523 |
524 | 1. 引入webpack
525 |
526 | ```js
527 | const webpack = require('webpack')
528 | ```
529 |
530 | 2. 创建插件对象
531 |
532 | ```js
533 | plugins: [
534 | new HtmlWebpackPlugin({
535 | filename: 'index.html',
536 | template: './src/index.html'
537 | }),
538 | new CleanWebpackPlugin(),
539 | new CopyWebpackPlugin([
540 | {
541 | from: path.join(__dirname, 'assets'),
542 | to: 'assets'
543 | }
544 | ]),
545 | new webpack.BannerPlugin('黑马程序员牛逼!')
546 | ],
547 | ```
548 |
549 |
550 | # 第3章 webpack高级配置
551 |
552 | ## HTML中img标签的图片资源处理
553 |
554 | 1. 安装`npm install -S html-withimg-loader`
555 |
556 | 2. 在`webpack.config.js`文件中添加loader
557 |
558 | ```js
559 | {
560 | test: /\.(htm|html)$/i,
561 | loader: 'html-withimg-loader'
562 | }
563 | ```
564 |
565 | 使用时,只需要在html中正常引用图片即可,webpack会找到对应的资源进行打包,并修改html中的引用路径
566 |
567 | ## 多页应用打包
568 |
569 | 1. 在`webpack.config.js`中修改入口和出口配置
570 |
571 | ```js
572 | // 1. 修改为多入口
573 | entry: {
574 | main: './src/main.js',
575 | other: './src/other.js'
576 | },
577 | output: {
578 | path: path.join(__dirname, './dist/'),
579 | // filename: 'bundle.js',
580 | // 2. 多入口无法对应一个固定的出口, 所以修改filename为[name]变量
581 | filename: '[name].js',
582 | publicPath: '/'
583 | },
584 | plugins: [
585 | // 3. 如果用了html插件,需要手动配置多入口对应的html文件,将指定其对应的输出文件
586 | new HtmlWebpackPlugin({
587 | template: './index.html',
588 | filename: 'index.html',
589 | chunks: ['main']
590 | }),
591 | new HtmlWebpackPlugin({
592 | template: './index.html',
593 | filename: 'other.html',
594 | // chunks: ['other', 'main']
595 | chunks: ['other']
596 | })
597 | ]
598 | ```
599 |
600 | 2. 修改入口为对象,支持多个js入口,同时修改output输出的文件名为`'[name].js'`表示各自已入口文件名作为输出文件名,但是`html-webpack-plugin`不支持此功能,所以需要再拷贝一份插件,用于生成两个html页面,实现多页应用
601 |
602 | ## 第三方库的两种引入方式
603 |
604 | 可以通过`expose-loader`进行全局变量的注入,同时也可以使用内置插件`webpack.ProvidePlugin`对每个模块的闭包空间,注入一个变量,自动加载模块,而不必到处 `import` 或 `require`
605 |
606 | - expose-loader **将库引入到全局作用域**
607 |
608 | 1. 安装`expose-loader`
609 |
610 | `npm i -D expose-loader`
611 |
612 | 2. 配置loader
613 |
614 | ```js
615 | module: {
616 | rules: [{
617 | test: require.resolve('jquery'),
618 | use: {
619 | loader: 'expose-loader',
620 | options: '$'
621 | }
622 | }]
623 | }
624 | ```
625 |
626 | tips: `require.resolve` 用来获取模块的绝对路径。所以这里的loader只会作用于 jquery 模块。并且只在 bundle 中使用到它时,才进行处理。
627 |
628 | - webpack.ProvidePlugin **将库自动加载到每个模块**
629 |
630 | 1. 引入webpack
631 |
632 | ```js
633 | const webpack = require('webpack')
634 | ```
635 |
636 | 2. 创建插件对象
637 |
638 | 要自动加载 `jquery`,我们可以将两个变量都指向对应的 node 模块
639 |
640 | ```js
641 | new webpack.ProvidePlugin({
642 | $: 'jquery',
643 | jQuery: 'jquery'
644 | })
645 | ```
646 |
647 | ## Development / Production不同配置文件打包
648 |
649 | 项目开发时一般需要使用两套配置文件,用于开发阶段打包(不压缩代码,不优化代码,增加效率)和上线阶段打包(压缩代码,优化代码,打包后直接上线使用)
650 |
651 | 抽取三个配置文件:
652 |
653 | - webpack.base.js
654 |
655 | - webpack.prod.js
656 |
657 | - webpack.dev.js
658 |
659 | 步骤如下:
660 |
661 | 1. 将开发环境和生产环境公用的配置放入base中,不同的配置各自放入prod或dev文件中(例如:mode)
662 |
663 | 2. 然后在dev和prod中使用`webpack-merge`把自己的配置与base的配置进行合并后导出
664 |
665 | `npm i -D webpack-merge`
666 |
667 | 3. 将package.json中的脚本参数进行修改,通过`--config`手动指定特定的配置文件
668 |
669 | ## 定义环境变量
670 |
671 | 除了区分不同的配置文件进行打包,还需要在开发时知道当前的环境是开发阶段或上线阶段,所以可以借助内置插件`DefinePlugin`来定义环境变量。最终可以实现开发阶段与上线阶段的api地址自动切换。
672 |
673 | 1. 引入webpack
674 |
675 | ```js
676 | const webpack = require('webpack')
677 | ```
678 |
679 | 2. 创建插件对象,并定义环境变量
680 |
681 | ```js
682 | new webpack.DefinePlugin({
683 | IS_DEV: 'false'
684 | })
685 | ```
686 |
687 | 3. 在src打包的代码环境下可以直接使用
688 |
689 | ## 使用devServer解决跨域问题
690 |
691 | 在开发阶段很多时候需要使用到跨域,何为跨域?请看下图:
692 |
693 | 
694 |
695 | 开发阶段往往会遇到上面这种情况,也许将来上线后,前端项目会和后端项目部署在同一个服务器下,并不会有跨域问题,但是由于开发时会用到webpack-dev-server,所以一定会产生跨域的问题
696 |
697 | 目前解决跨域主要的方案有:
698 |
699 | 1. jsonp(淘汰)
700 | 2. cors
701 | 3. http proxy
702 |
703 | 此处介绍的使用devServer解决跨域,其实原理就是http proxy
704 |
705 | 将所有ajax请求发送给devServer服务器,再由devServer服务器做一次转发,发送给数据接口服务器
706 |
707 | 由于ajax请求是发送给devServer服务器的,所以不存在跨域,而devServer由于是用node平台发送的http请求,自然也不涉及到跨域问题,可以完美解决!
708 |
709 | 
710 |
711 | 服务器代码(返回一段字符串即可):
712 |
713 | ```js
714 | const express = require('express')
715 | const app = express()
716 | // const cors = require('cors')
717 | // app.use(cors())
718 | app.get('/api/getUserInfo', (req, res) => {
719 | res.send({
720 | name: '黑马儿',
721 | age: 13
722 | })
723 | });
724 |
725 | app.listen(9999, () => {
726 | console.log('http://localhost:9999!');
727 | });
728 | ```
729 |
730 | 前端需要配置devServer的proxy功能,在`webpack.dev.js`中进行配置:
731 |
732 | ```js
733 | devServer: {
734 | open: true,
735 | hot: true,
736 | compress: true,
737 | port: 3000,
738 | // contentBase: './src'
739 | proxy: {
740 | '/api': 'http://localhost:9999'
741 | }
742 | },
743 | ```
744 |
745 | 意为前端请求`/api`的url时,webpack-dev-server会将请求转发给`http://localhost:9999/api`处,此时如果请求地址为`http://localhost:9999/api/getUserInfo`,只需要直接写`/api/getUserInfo`即可,代码如下:
746 |
747 | ```js
748 | axios.get('/api/getUserInfo').then(result => console.log(result))
749 | ```
750 |
751 | ## HMR的使用
752 |
753 | 需要对某个模块进行热更新时,可以通过`module.hot.accept`方法进行文件监视
754 |
755 | 只要模块内容发生变化,就会触发回调函数,从而可以重新读取模块内容,做对应的操作
756 |
757 | ```js
758 | if (module.hot) {
759 | module.hot.accept('./hotmodule.js', function() {
760 | console.log('hotmodule.js更新了');
761 | let str = require('./hotmodule.js')
762 | console.log(str)
763 | })
764 | }
765 | ```
766 |
767 | # 第4章 webpack优化
768 |
769 | ## production模式打包自带优化
770 |
771 | - tree shaking
772 |
773 | tree shaking 是一个术语,通常用于打包时移除 JavaScript 中的未引用的代码(dead-code),它依赖于 ES6 模块系统中 `import`和 `export`的**静态结构**特性。
774 |
775 | 开发时引入一个模块后,如果只使用其中一个功能,上线打包时只会把用到的功能打包进bundle,其他没用到的功能都不会打包进来,可以实现最基础的优化
776 |
777 |
778 |
779 | - scope hoisting
780 |
781 | scope hoisting的作用是将模块之间的关系进行结果推测, 可以让 Webpack 打包出来的代码文件更小、运行的更快
782 |
783 | scope hoisting 的实现原理其实很简单:分析出模块之间的依赖关系,尽可能的把打散的模块合并到一个函数中去,但前提是不能造成代码冗余。
784 | 因此只有那些被引用了一次的模块才能被合并。
785 |
786 | 由于 scope hoisting 需要分析出模块之间的依赖关系,因此源码必须采用 ES6 模块化语句,不然它将无法生效。
787 | 原因和tree shaking一样。
788 |
789 |
790 |
791 | - 代码压缩
792 |
793 | 所有代码使用UglifyJsPlugin插件进行压缩、混淆
794 |
795 | ## css优化
796 |
797 | ### 将css提取到独立的文件中
798 |
799 | `mini-css-extract-plugin`是用于将CSS提取为独立的文件的插件,对每个包含css的js文件都会创建一个CSS文件,支持按需加载css和sourceMap
800 |
801 | 只能用在webpack4中,有如下优势:
802 |
803 | - 异步加载
804 | - 不重复编译,性能很好
805 | - 容易使用
806 | - 只针对CSS
807 |
808 | 使用方法:
809 |
810 | 1. 安装
811 |
812 | `npm i -D mini-css-extract-plugin`
813 |
814 | 2. 在webpack配置文件中引入插件
815 |
816 | ```js
817 | const MiniCssExtractPlugin = require('mini-css-extract-plugin')
818 | ```
819 |
820 | 3. 创建插件对象,配置抽离的css文件名,支持placeholder语法
821 |
822 | ```js
823 | new MiniCssExtractPlugin({
824 | filename: '[name].css'
825 | })
826 | ```
827 |
828 | 4. 将原来配置的所有`style-loader`替换为`MiniCssExtractPlugin.loader`
829 |
830 | ```js
831 | {
832 | test: /\.css$/,
833 | // webpack读取loader时 是从右到左的读取, 会将css文件先交给最右侧的loader来处理
834 | // loader的执行顺序是从右到左以管道的方式链式调用
835 | // css-loader: 解析css文件
836 | // style-loader: 将解析出来的结果 放到html中, 使其生效
837 | // use: ['style-loader', 'css-loader']
838 | use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']
839 | },
840 | // { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
841 | { test: /\.less$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'] },
842 | // { test: /\.s(a|c)ss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
843 | { test: /\.s(a|c)ss$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'] },
844 | ```
845 |
846 |
847 | ### 自动添加css前缀
848 |
849 | 使用`postcss`,需要用到`postcss-loader`和`autoprefixer`插件
850 |
851 | 1. 安装
852 |
853 | `npm i -D postcss-loader autoprefixer`
854 |
855 | 2. 修改webpack配置文件中的loader,将`postcss-loader`放置在`css-loader`的右边(调用链从右到左)
856 |
857 | ```js
858 | {
859 | test: /\.css$/,
860 | // webpack读取loader时 是从右到左的读取, 会将css文件先交给最右侧的loader来处理
861 | // loader的执行顺序是从右到左以管道的方式链式调用
862 | // css-loader: 解析css文件
863 | // style-loader: 将解析出来的结果 放到html中, 使其生效
864 | // use: ['style-loader', 'css-loader']
865 | use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']
866 | },
867 | // { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
868 | { test: /\.less$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader'] },
869 | // { test: /\.s(a|c)ss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
870 | { test: /\.s(a|c)ss$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'] },
871 | ```
872 |
873 | 3. 项目根目录下添加`postcss`的配置文件:`postcss.config.js`
874 |
875 | 4. 在`postcss`的配置文件中使用插件
876 |
877 | ```js
878 | module.exports = {
879 | plugins: [require('autoprefixer')]
880 | }
881 | ```
882 |
883 | ### 开启css压缩
884 |
885 | 需要使用`optimize-css-assets-webpack-plugin`插件来完成css压缩
886 |
887 | 但是由于配置css压缩时会覆盖掉webpack默认的优化配置,导致JS代码无法压缩,所以还需要手动把JS代码压缩插件导入进来:`terser-webpack-plugin`
888 |
889 | 1. 安装
890 |
891 | `npm i -D optimize-css-assets-webpack-plugin terser-webpack-plugin `
892 |
893 | 2. 导入插件
894 |
895 | ```js
896 | const TerserJSPlugin = require('terser-webpack-plugin')
897 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
898 | ```
899 |
900 | 3. 在webpack配置文件中添加配置节点
901 |
902 | ```js
903 | optimization: {
904 | minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
905 | },
906 | ```
907 |
908 | tips: webpack4默认采用的JS压缩插件为:`uglifyjs-webpack-plugin`,在`mini-css-extract-plugin`上一个版本中还推荐使用该插件,但最新的v0.6中建议使用`teser-webpack-plugin`来完成js代码压缩,具体原因未在官网说明,我们就按照最新版的官方文档来做即可
909 |
910 | ## js代码分离
911 |
912 | Code Splitting是webpack打包时用到的重要的优化特性之一,此特性能够把代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件。代码分离可以用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间。
913 |
914 | 有三种常用的代码分离方法:
915 |
916 | - 入口起点(entry points):使用`entry`配置手动地分离代码。
917 | - 防止重复(prevent duplication):使用 `SplitChunksPlugin`去重和分离 chunk。
918 | - 动态导入(dynamic imports):通过模块的内联函数调用来分离代码。
919 |
920 | ### 手动配置多入口
921 |
922 | 1. 在webpack配置文件中配置多个入口
923 |
924 | ```js
925 | entry: {
926 | main: './src/main.js',
927 | other: './src/other.js'
928 | },
929 | output: {
930 | // path.resolve() : 解析当前相对路径的绝对路径
931 | // path: path.resolve('./dist/'),
932 | // path: path.resolve(__dirname, './dist/'),
933 | path: path.join(__dirname, '..', './dist/'),
934 | // filename: 'bundle.js',
935 | filename: '[name].bundle.js',
936 | publicPath: '/'
937 | },
938 | ```
939 |
940 | 2. 在main.js和other.js中都引入同一个模块,并使用其功能
941 |
942 | main.js
943 |
944 | ```js
945 | import $ from 'jquery'
946 |
947 | $(function() {
948 | $('').html('main').appendTo('body')
949 | })
950 | ```
951 |
952 | other.js
953 |
954 | ```js
955 | import $ from 'jquery'
956 |
957 | $(function() {
958 | $('').html('other').appendTo('body')
959 | })
960 | ```
961 |
962 | 3. 修改package.json的脚本,添加一个使用dev配置文件进行打包的脚本(目的是不压缩代码检查打包的bundle时更方便)
963 |
964 | ```json
965 | "scripts": {
966 | "build": "webpack --config ./build/webpack.prod.js",
967 | "dev-build": "webpack --config ./build/webpack.dev.js"
968 | }
969 | ```
970 |
971 | 4. 运行`npm run dev-build`,进行打包
972 |
973 | 5. 查看打包后的结果,发现other.bundle.js和main.bundle.js都同时打包了jQuery源文件
974 |
975 | 
976 |
977 | 
978 |
979 | 这种方法存在一些问题:
980 |
981 | - 如果入口 chunks 之间包含重复的模块,那些重复模块都会被引入到各个 bundle 中。
982 | - 这种方法不够灵活,并且不能将核心应用程序逻辑进行动态拆分代码。
983 |
984 | ### 抽取公共代码
985 |
986 | tips: Webpack v4以上使用的插件为`SplitChunksPlugin`,以前使用的`CommonsChunkPlugin`已经被移除了,最新版的webpack只需要在配置文件中的`optimization`节点下添加一个`splitChunks`属性即可进行相关配置
987 |
988 | 1. 修改webpack配置文件
989 |
990 | ```js
991 | optimization: {
992 | splitChunks: {
993 | chunks: 'all'
994 | }
995 | },
996 | ```
997 |
998 | 2. 运行`npm run dev-build`重新打包
999 |
1000 | 3. 查看`dist`目录
1001 |
1002 | 
1003 |
1004 | 4. 查看`vendors~main~other.bundle.js`,其实就是把都用到的jQuery打包到了一个单独的js中
1005 |
1006 | 
1007 |
1008 | ### 动态导入 (懒加载)
1009 |
1010 | webpack4默认是允许import语法动态导入的,但是需要babel的插件支持,最新版babel的插件包为:`@babel/plugin-syntax-dynamic-import`,以前老版本不是`@babel`开头,已经无法使用,需要注意
1011 |
1012 | 动态导入最大的好处是实现了懒加载,用到哪个模块才会加载哪个模块,可以提高SPA应用程序的首屏加载速度,Vue、React、Angular框架的路由懒加载原理一样
1013 |
1014 | 1. 安装babel插件
1015 |
1016 | `npm install -D @babel/plugin-syntax-dynamic-import`
1017 |
1018 | 2. 修改.babelrc配置文件,添加`@babel/plugin-syntax-dynamic-import`插件
1019 |
1020 | ```json
1021 | {
1022 | "presets": ["@babel/env"],
1023 | "plugins": [
1024 | "@babel/plugin-proposal-class-properties",
1025 | "@babel/plugin-transform-runtime",
1026 | "@babel/plugin-syntax-dynamic-import"
1027 | ]
1028 | }
1029 | ```
1030 |
1031 | 3. 将jQuery模块进行动态导入
1032 |
1033 | ```js
1034 | function getComponent() {
1035 | return import('jquery').then(({ default: $ }) => {
1036 | return $('').html('main')
1037 | })
1038 | }
1039 | ```
1040 |
1041 | 4. 给某个按钮添加点击事件,点击后调用getComponent函数创建元素并添加到页面
1042 |
1043 | ```js
1044 | window.onload = function () {
1045 | document.getElementById('btn').onclick = function () {
1046 | getComponent().then(item => {
1047 | item.appendTo('body')
1048 | })
1049 | }
1050 | }
1051 | ```
1052 |
1053 |
1054 |
1055 | ### SplitChunksPlugin配置参数
1056 |
1057 | webpack4之后,使用`SplitChunksPlugin`插件替代了以前`CommonsChunkPlugin`
1058 |
1059 | 而`SplitChunksPlugin`的配置,只需要在webpack配置文件中的`optimization`节点下的`splitChunks`进行修改即可,如果没有任何修改,则会使用默认配置
1060 |
1061 | 默认的`SplitChunksPlugin` 配置适用于绝大多数用户
1062 |
1063 | webpack 会基于如下默认原则自动分割代码:
1064 |
1065 | - 公用代码块或来自 *node_modules* 文件夹的组件模块。
1066 | - 打包的代码块大小超过 30k(最小化压缩之前)。
1067 | - 按需加载代码块时,同时发送的请求最大数量不应该超过 5。
1068 | - 页面初始化时,同时发送的请求最大数量不应该超过 3。
1069 |
1070 | 以下是`SplitChunksPlugin`的默认配置:
1071 |
1072 | ```js
1073 | module.exports = {
1074 | //...
1075 | optimization: {
1076 | splitChunks: {
1077 | chunks: 'async', // 只对异步加载的模块进行拆分,可选值还有all | initial
1078 | minSize: 30000, // 模块最少大于30KB才拆分
1079 | maxSize: 0, // 模块大小无上限,只要大于30KB都拆分
1080 | minChunks: 1, // 模块最少引用一次才会被拆分
1081 | maxAsyncRequests: 5, // 异步加载时同时发送的请求数量最大不能超过5,超过5的部分不拆分
1082 | maxInitialRequests: 3, // 页面初始化时同时发送的请求数量最大不能超过3,超过3的部分不拆分
1083 | automaticNameDelimiter: '~', // 默认的连接符
1084 | name: true, // 拆分的chunk名,设为true表示根据模块名和CacheGroup的key来自动生成,使用上面连接符连接
1085 | cacheGroups: { // 缓存组配置,上面配置读取完成后进行拆分,如果需要把多个模块拆分到一个文件,就需要缓存,所以命名为缓存组
1086 | vendors: { // 自定义缓存组名
1087 | test: /[\\/]node_modules[\\/]/, // 检查node_modules目录,只要模块在该目录下就使用上面配置拆分到这个组
1088 | priority: -10 // 权重-10,决定了哪个组优先匹配,例如node_modules下有个模块要拆分,同时满足vendors和default组,此时就会分到vendors组,因为-10 > -20
1089 | },
1090 | default: { // 默认缓存组名
1091 | minChunks: 2, // 最少引用两次才会被拆分
1092 | priority: -20, // 权重-20
1093 | reuseExistingChunk: true // 如果主入口中引入了两个模块,其中一个正好也引用了后一个,就会直接复用,无需引用两次
1094 | }
1095 | }
1096 | }
1097 | }
1098 | };
1099 | ```
1100 |
1101 | ## noParse
1102 |
1103 | 在引入一些第三方模块时,例如jQuery、bootstrap等,我们知道其内部肯定不会依赖其他模块,因为最终我们用到的只是一个单独的js文件或css文件
1104 |
1105 | 所以此时如果webpack再去解析他们的内部依赖关系,其实是非常浪费时间的,我们需要阻止webpack浪费精力去解析这些明知道没有依赖的库
1106 |
1107 | 可以在webpack配置文件的`module`节点下加上`noParse`,并配置正则来确定不需要解析依赖关系的模块
1108 |
1109 | ```js
1110 | module: {
1111 | noParse: /jquery|bootstrap/
1112 | }
1113 | ```
1114 |
1115 | ## IgnorePlugin
1116 |
1117 | 在引入一些第三方模块时,例如moment,内部会做i18n国际化处理,所以会包含很多语言包,而语言包打包时会比较占用空间,如果我们项目只需要用到中文,或者少数语言,可以忽略掉所有的语言包,然后按需引入语言包
1118 |
1119 | 从而使得构建效率更高,打包生成的文件更小
1120 |
1121 | 需要忽略第三方模块内部依赖的其他模块,只需要三步:
1122 |
1123 | 1. 首先要找到moment依赖的语言包是什么
1124 | 2. 使用IgnorePlugin插件忽略其依赖
1125 | 3. 需要使用某些依赖时自行手动引入
1126 |
1127 | 具体实现如下:
1128 |
1129 | 1. 通过查看moment的源码来分析:
1130 |
1131 | ```js
1132 | function loadLocale(name) {
1133 | var oldLocale = null;
1134 | // TODO: Find a better way to register and load all the locales in Node
1135 | if (!locales[name] && (typeof module !== 'undefined') &&
1136 | module && module.exports) {
1137 | try {
1138 | oldLocale = globalLocale._abbr;
1139 | var aliasedRequire = require;
1140 | aliasedRequire('./locale/' + name);
1141 | getSetGlobalLocale(oldLocale);
1142 | } catch (e) {}
1143 | }
1144 | return locales[name];
1145 | }
1146 |
1147 | ```
1148 |
1149 | 观察上方代码,同时查看moment目录下确实有locale目录,其中放着所有国家的语言包,可以分析得出:locale目录就是moment所依赖的语言包目录
1150 |
1151 | 2. 使用IgnorePlugin插件来忽略掉moment模块的locale目录
1152 |
1153 | 在webpack配置文件中安装插件,并传入配置项
1154 |
1155 | 参数1:表示要忽略的资源路径
1156 |
1157 | 参数2:要忽略的资源上下文(所在哪个目录)
1158 |
1159 | 两个参数都是正则对象
1160 |
1161 | ```js
1162 | new webpack.IgnorePlugin(/\.\/locale/, /moment/)
1163 | ```
1164 |
1165 | 3. 使用moment时需要手动引入语言包,否则默认使用英文
1166 |
1167 | ```js
1168 | import moment from 'moment'
1169 | import 'moment/locale/zh-cn'
1170 | moment.locale('zh-CN')
1171 | console.log(moment().subtract(6, 'days').calendar())
1172 | ```
1173 |
1174 | ## DllPlugin
1175 |
1176 | 在引入一些第三方模块时,例如vue、react、angular等框架,这些框架的文件一般都是不会修改的,而每次打包都需要去解析它们,也会影响打包速度,哪怕做拆分,也只是提高了上线后用户访问速度,并不会提高构建速度,所以如果需要提高构建速度,应该使用动态链接库的方式,类似于Windows中的dll文件。
1177 |
1178 | 借助DllPlugin插件实现将这些框架作为一个个的动态链接库,只构建一次,以后每次构建都只生成自己的业务代码,可以大大提高构建效率!
1179 |
1180 | 主要思想在于,将一些不做修改的依赖文件,提前打包,这样我们开发代码发布的时候就不需要再对这部分代码进行打包,从而节省了打包时间。
1181 |
1182 | 涉及两个插件:
1183 |
1184 | 1. DllPlugin
1185 |
1186 | 使用一个单独webpack配置创建一个dll文件。并且它还创建一个manifest.json。DllReferencePlugin使用该json文件来做映射依赖性。(这个文件会告诉我们的哪些文件已经提取打包好了)
1187 |
1188 | 配置参数:
1189 |
1190 | - context (可选): manifest文件中请求的上下文,默认为该webpack文件上下文。
1191 | - name: 公开的dll函数的名称,和output.library保持一致即可。
1192 | - path: manifest.json生成的文件夹及名字
1193 |
1194 | 2. DllReferencePlugin
1195 |
1196 | 这个插件用于主webpack配置,它引用的dll需要预先构建的依赖关系。
1197 |
1198 | - context: manifest文件中请求的上下文。
1199 |
1200 | - manifest: DllPlugin插件生成的manifest.json
1201 |
1202 | - content(可选): 请求的映射模块id(默认为manifest.content)
1203 |
1204 | - name(可选): dll暴露的名称
1205 |
1206 | - scope(可选): 前缀用于访问dll的内容
1207 |
1208 | - sourceType(可选): dll是如何暴露(libraryTarget)
1209 |
1210 | ### 将Vue项目中的库抽取成Dll
1211 |
1212 | 1. 准备一份将Vue打包成DLL的webpack配置文件
1213 |
1214 | 在build目录下新建一个文件:webpack.vue.js
1215 |
1216 | 配置入口:将多个要做成dll的库全放进来
1217 |
1218 | 配置出口:一定要设置library属性,将打包好的结果暴露在全局
1219 |
1220 | 配置plugin:设置打包后dll文件名和manifest文件所在地
1221 |
1222 | ```js
1223 | const path = require('path')
1224 | const webpack = require('webpack')
1225 | module.exports = {
1226 | mode: 'development',
1227 | entry: {
1228 | vue: [
1229 | 'vue/dist/vue.js',
1230 | 'vue-router'
1231 | ]
1232 | },
1233 | output: {
1234 | filename: '[name]_dll.js',
1235 | path: path.resolve(__dirname, '../dist'),
1236 | library: '[name]_dll'
1237 | },
1238 | plugins: [
1239 | new webpack.DllPlugin({
1240 | name: '[name]_dll',
1241 | path: path.resolve(__dirname, '../dist/manifest.json')
1242 | })
1243 | ]
1244 | }
1245 | ```
1246 |
1247 | 2. 在webpack.base.js中进行插件的配置
1248 |
1249 | 使用DLLReferencePlugin指定manifest文件的位置即可
1250 |
1251 | ```js
1252 | new webpack.DllReferencePlugin({
1253 | manifest: path.resolve(__dirname, '../dist/manifest.json')
1254 | })
1255 | ```
1256 |
1257 | 3. 安装add-asset-html-webpack-plugin
1258 |
1259 | `npm i add-asset-html-webpack-plugin -D`
1260 |
1261 | 4. 配置插件自动添加script标签到HTML中
1262 |
1263 | ```js
1264 | new AddAssetHtmlWebpackPlugin({
1265 | filepath: path.resolve(__dirname, '../dist/vue_dll.js')
1266 | })
1267 | ```
1268 |
1269 | ### 将React项目中的库抽取成Dll
1270 |
1271 | 1. 准备一份将React打包成DLL的webpack配置文件
1272 |
1273 | 在build目录下新建一个文件:webpack.vue.js
1274 |
1275 | 配置入口:将多个要做成dll的库全放进来
1276 |
1277 | 配置出口:一定要设置library属性,将打包好的结果暴露在全局
1278 |
1279 | 配置plugin:设置打包后dll文件名和manifest文件所在地
1280 |
1281 | ```js
1282 | const path = require('path')
1283 | const webpack = require('webpack')
1284 | module.exports = {
1285 | mode: 'development',
1286 | entry: {
1287 | react: [
1288 | 'react',
1289 | 'react-dom'
1290 | ]
1291 | },
1292 | output: {
1293 | filename: '[name]_dll.js',
1294 | path: path.resolve(__dirname, '../dist'),
1295 | library: '[name]_dll'
1296 | },
1297 | plugins: [
1298 | new webpack.DllPlugin({
1299 | name: '[name]_dll',
1300 | path: path.resolve(__dirname, '../dist/manifest.json')
1301 | })
1302 | ]
1303 | }
1304 | ```
1305 |
1306 | 2. 在webpack.base.js中进行插件的配置
1307 |
1308 | 使用DLLReferencePlugin指定manifest文件的位置即可
1309 |
1310 | ```js
1311 | new webpack.DllReferencePlugin({
1312 | manifest: path.resolve(__dirname, '../dist/manifest.json')
1313 | })
1314 | ```
1315 |
1316 | 3. 安装add-asset-html-webpack-plugin
1317 |
1318 | `npm i add-asset-html-webpack-plugin -D`
1319 |
1320 | 4. 配置插件自动添加script标签到HTML中
1321 |
1322 | ```js
1323 | new AddAssetHtmlWebpackPlugin({
1324 | filepath: path.resolve(__dirname, '../dist/react_dll.js')
1325 | })
1326 | ```
1327 |
1328 |
1329 | ## Happypack
1330 |
1331 | 
1332 |
1333 | 由于webpack在node环境中运行打包构建,所以是单线程的模式,在打包众多资源时效率会比较低下,早期可以通过`Happypack`来实现多进程打包。当然,这个问题只出现在低版本的webpack中,现在的webpack性能已经非常强劲了,所以无需使用Happypack也可以实现高性能打包
1334 |
1335 | [Happypack官网]( https://github.com/amireh/happypack)
1336 |
1337 | 引用官网原文:
1338 |
1339 | > **Maintenance mode notice**
1340 | >
1341 | > My interest in the project is fading away mainly because I'm not using JavaScript as much as I was in the past. Additionally, Webpack's native performance is improving and (I hope) it will soon make this plugin unnecessary.
1342 | >
1343 | > See the FAQ entry about Webpack 4 and [thread-loader](https://github.com/webpack-contrib/thread-loader).
1344 | >
1345 | > Contributions are always welcome. Changes I make from this point will be restricted to bug-fixing. If someone wants to take over, feel free to get in touch.
1346 | >
1347 | > Thanks to everyone who used the library, contributed to it and helped in refining it!!!
1348 |
1349 | 由此可以看出作者已经发现,webpack的性能已经强大到不需要使用该插件了,而且小项目使用该插件反而会导致性能损耗过大,因为开启进程是需要耗时的
1350 |
1351 | 使用方法:
1352 |
1353 | 1. 安装插件
1354 |
1355 | `npm i -D happypack`
1356 |
1357 | 2. 在webpack配置文件中引入插件
1358 |
1359 | ```js
1360 | const HappyPack = require('happypack')
1361 | ```
1362 |
1363 | 3. 修改loader的配置规则
1364 |
1365 | ```js
1366 | {
1367 | test: /.js$/,
1368 | use: {
1369 | loader: 'happypack/loader'
1370 | },
1371 | include: path.resolve(__dirname, '../src'),
1372 | exclude: /node_modules/
1373 | }
1374 | ```
1375 |
1376 | 4. 配置插件
1377 |
1378 | ```js
1379 | new HappyPack({
1380 | loaders: [ 'babel-loader' ]
1381 | })
1382 | ```
1383 |
1384 | 5. 运行打包命令
1385 |
1386 | `npm run build`
1387 |
1388 | ## 浏览器缓存
1389 |
1390 | 在做了众多代码分离的优化后,其目的是为了利用浏览器缓存,达到提高访问速度的效果,所以构建项目时做代码分割是必须的,例如将固定的第三方模块抽离,下次修改了业务代码,重新发布上线不重启服务器,用户再次访问服务器就不需要再次加载第三方模块了
1391 |
1392 | 但此时会遇到一个新的问题,如果再次打包上线不重启服务器,客户端会把以前的业务代码和第三方模块同时缓存,再次访问时依旧会访问缓存中的业务代码,所以会导致业务代码也无法更新
1393 |
1394 | 需要在output节点的filename中使用placeholder语法,根据代码内容生成文件名的hash:
1395 |
1396 | ```js
1397 | output: {
1398 | // path.resolve() : 解析当前相对路径的绝对路径
1399 | // path: path.resolve('./dist/'),
1400 | // path: path.resolve(__dirname, './dist/'),
1401 | path: path.join(__dirname, '..', './dist/'),
1402 | // filename: 'bundle.js',
1403 | filename: '[name].[contenthash:8].bundle.js',
1404 | publicPath: '/'
1405 | },
1406 | ```
1407 |
1408 | 之后每次打包业务代码时,如果有改变,会生成新的hash作为文件名,浏览器就不会使用缓存了,而第三方模块不会重新打包生成新的名字,则会继续使用缓存
1409 |
1410 | ## 打包分析
1411 |
1412 | 项目构建完成后,需要通过一些工具对打包后的bundle进行分析,通过分析才能总结出一些经验,官方推荐的分析方法有两步完成:
1413 |
1414 | 1. 使用`--profile --json`参数,以json格式来输出打包后的结果到某个指定文件中
1415 |
1416 | `webpack --profile --json > stats.json`
1417 |
1418 | 2. 将stats.json文件放入工具中进行分析
1419 |
1420 | 官方工具:[official analyze tool](https://github.com/webpack/analyse)
1421 |
1422 | 官方推荐的其他四个工具:
1423 |
1424 | - [webpack-chart](https://alexkuz.github.io/webpack-chart/)
1425 | - [webpack-visualizer](https://chrisbateman.github.io/webpack-visualizer/)
1426 | - [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer)
1427 | - [webpack bundle optimize helper](https://webpack.jakoblind.no/optimize)
1428 |
1429 | 其中webpack-bundle-analyzer是一个插件,可以以插件的方式安装到项目中
1430 |
1431 | ## Prefetching和Preloading
1432 |
1433 | 在优化访问性能时,除了充分利用浏览器缓存之外,还需要涉及一个性能指标:coverage rate(覆盖率)
1434 |
1435 | 可以在Chrome浏览器的控制台中按:ctrl + shift + p,查找coverage,打开覆盖率面板
1436 |
1437 | 开始录制后刷新网页,即可看到每个js文件的覆盖率,以及总的覆盖率
1438 |
1439 | 
1440 |
1441 | 想提高覆盖率,需要尽可能多的使用动态导入,也就是懒加载功能,将一切能使用懒加载的地方都是用懒加载,这样可以大大提高覆盖率
1442 |
1443 | 但有时候使用懒加载会影响用户体验,所以可以在懒加载时使用魔法注释:Prefetching,是指在首页资源加载完毕后,空闲时间时,将动态导入的资源加载进来,这样即可以提高首屏加载速度,也可以解决懒加载可能会影响用户体验的问题,一举两得!
1444 |
1445 | ```js
1446 | function getComponent() {
1447 | return import(/* webpackPrefetch: true */ 'jquery').then(({ default: $ }) => {
1448 | return $('').html('我是main')
1449 | })
1450 | }
1451 | ```
1452 |
1453 |
1454 |
1455 | # 第5章 webpack原理
1456 |
1457 | ## 学习目标
1458 |
1459 | - 了解webpack打包原理
1460 | - 了解webpack的loader原理
1461 | - 了解webpack的插件原理
1462 | - 了解ast抽象语法树的应用
1463 | - 了解tapable的原理
1464 | - 手写一个简单的webpack
1465 |
1466 | ## 项目准备工作
1467 |
1468 | 1. 新建一个项目,起一个炫酷的名字
1469 |
1470 | 2. 新建`bin`目录,将打包工具主程序放入其中
1471 |
1472 | 主程序的顶部应当有:`#!/usr/bin/env node`标识,指定程序执行环境为node
1473 |
1474 | 3. 在`package.json`中配置`bin`脚本
1475 |
1476 | ```json
1477 | {
1478 | "bin": "./bin/itheima-pack.js"
1479 | }
1480 | ```
1481 |
1482 | 4. 通过`npm link`链接到全局包中,供本地测试使用
1483 |
1484 | ## 分析webpack打包的bundle文件
1485 |
1486 | 其内部就是自己实现了一个`__webpack_require__`函数,递归导入依赖关系
1487 |
1488 | ```js
1489 | (function (modules) { // webpackBootstrap
1490 | // The module cache
1491 | var installedModules = {};
1492 |
1493 | // The require function
1494 | function __webpack_require__(moduleId) {
1495 |
1496 | // Check if module is in cache
1497 | if (installedModules[moduleId]) {
1498 | return installedModules[moduleId].exports;
1499 | }
1500 | // Create a new module (and put it into the cache)
1501 | var module = installedModules[moduleId] = {
1502 | i: moduleId,
1503 | l: false,
1504 | exports: {}
1505 | };
1506 |
1507 | // Execute the module function
1508 | modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
1509 |
1510 | // Flag the module as loaded
1511 | module.l = true;
1512 |
1513 | // Return the exports of the module
1514 | return module.exports;
1515 | }
1516 |
1517 | // Load entry module and return exports
1518 | return __webpack_require__(__webpack_require__.s = "./src/index.js");
1519 | })
1520 | ({
1521 | "./src/index.js":
1522 | (function (module, exports, __webpack_require__) {
1523 | eval("let news = __webpack_require__(/*! ./news.js */ \"./src/news.js\")\r\nconsole.log(news.content)\n\n//# sourceURL=webpack:///./src/index.js?");
1524 | }),
1525 | "./src/message.js":
1526 | (function (module, exports) {
1527 | eval("module.exports = {\r\n content: '今天要下雨了!!!'\r\n}\n\n//# sourceURL=webpack:///./src/message.js?");
1528 | }),
1529 | "./src/news.js":
1530 | (function (module, exports, __webpack_require__) {
1531 | eval("let message = __webpack_require__(/*! ./message.js */ \"./src/message.js\")\r\n\r\nmodule.exports = {\r\n content: '今天有个大新闻,爆炸消息!!!内容是:' + message.content\r\n}\n\n//# sourceURL=webpack:///./src/news.js?");
1532 | })
1533 | });
1534 | ```
1535 |
1536 | ## 自定义loader
1537 |
1538 | ### 学习目标
1539 |
1540 | 在学习给自己写的itheima-pack工具添加loader功能之前,得先学习webpack中如何自定义loader,所以学习步骤分为两大步:
1541 |
1542 | 1. 掌握自定义webpack的loader
1543 | 2. 学习给itheima-pack添加loader功能并写一个loader
1544 |
1545 | webpack以及我们自己写的itheima-pack都只能处理JavaScript文件,如果需要处理其他文件,或者对JavaScript代码做一些操作,则需要用到loader。
1546 |
1547 | loader是webpack中四大核心概念之一,主要功能是将一段匹配规则的代码进行加工处理,生成最终的代码后输出,是webpack打包环节中非常重要的一环。
1548 |
1549 | > loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
1550 |
1551 | 之前都使用过别人写好的loader,步骤大致分为:
1552 |
1553 | 1. 装包
1554 | 2. 在webpack.config.js中配置module节点下的rules即可,例如babel-loader(省略其他配置,只论loader)
1555 | 3. (可选步骤)可能还需要其他的配置,例如babel需要配置presets和plugin
1556 |
1557 | ```js
1558 | const path = require('path')
1559 |
1560 | module.exports = {
1561 | entry: './src/index.js',
1562 | output: {
1563 | path: path.join(__dirname, 'dist'),
1564 | filename: 'bundle.js'
1565 | },
1566 | module: {
1567 | rules: [
1568 | { test: /\.js$/, use: 'babel-loader' }
1569 | ]
1570 | },
1571 | mode: 'development'
1572 | }
1573 | ```
1574 |
1575 | ### 实现一个简单的loader
1576 |
1577 | loader到底是什么东西?能不能自己写?
1578 |
1579 | 答案是肯定的,loader就是一个函数,同样也可以自己来写
1580 |
1581 | 1. 在项目根目录中新建一个目录存放自己写的loader:
1582 |
1583 | 
1584 |
1585 | 2. 编写myloader.js,其实loader就是对外暴露一个函数
1586 |
1587 | 第一个参数就是loader要处理的代码
1588 |
1589 | ```js
1590 | module.exports = function(source) {
1591 | console.log(source) // 只是简单打印并返回结果,不作任何处理
1592 | return source
1593 | }
1594 | ```
1595 |
1596 | 3. 同样在webpack.config.js中配置自己写的loader,为了方便演示,直接匹配所有的js文件使用自己的myloader进行处理
1597 |
1598 | ```js
1599 | const path = require('path')
1600 |
1601 | module.exports = {
1602 | entry: './src/index.js',
1603 | output: {
1604 | path: path.join(__dirname, 'dist'),
1605 | filename: 'bundle.js'
1606 | },
1607 | module: {
1608 | rules: [
1609 | { test: /.js$/, use: './loaders/myloader.js' }
1610 | ]
1611 | },
1612 | mode: 'development'
1613 | }
1614 | ```
1615 |
1616 | 4. 如果需要实现一个简单的loader,例如将js中所有的“今天”替换成“明天”
1617 |
1618 | 只需要修改myloader.js的内容如下即可
1619 |
1620 | ```js
1621 | module.exports = function(source) {
1622 | return source.replace(/今天/g, '明天')
1623 | }
1624 | ```
1625 |
1626 | 5. 同时也可以配置多个loader对代码进行处理
1627 |
1628 | ```js
1629 | const path = require('path')
1630 |
1631 | module.exports = {
1632 | entry: './src/index.js',
1633 | output: {
1634 | path: path.join(__dirname, 'dist'),
1635 | filename: 'bundle.js'
1636 | },
1637 | module: {
1638 | rules: [
1639 | { test: /.js$/, use: ['./loaders/myloader2.js', './loaders/myloader.js'] }
1640 | ]
1641 | },
1642 | mode: 'development'
1643 | }
1644 | ```
1645 |
1646 | 6. myloader2.js
1647 |
1648 | ```js
1649 | module.exports = function(source) {
1650 | return source.replace(/爆炸/g, '小道')
1651 | }
1652 | ```
1653 |
1654 | ### loader的分类
1655 |
1656 | 不同类型的loader加载时优先级不同,优先级顺序遵循:
1657 |
1658 | 前置 > 行内 > 普通 > 后置
1659 |
1660 | pre: 前置loader
1661 |
1662 | post: 后置loader
1663 |
1664 | 指定Rule.enforce的属性即可设置loader的种类,不设置默认为普通loader
1665 |
1666 | ### 在itheima-pack中添加loader的功能
1667 |
1668 | 通过配置loader和手写loader可以发现,其实webpack能支持loader,主要步骤如下:
1669 |
1670 | 1. 读取webpack.config.js配置文件的module.rules配置项,进行倒序迭代(rules的每项匹配规则按倒序匹配)
1671 | 2. 根据正则匹配到对应的文件类型,同时再批量导入loader函数
1672 | 3. 倒序迭代调用所有loader函数(loader的加载顺序从右到左,也是倒叙)
1673 | 4. 最后返回处理后的代码
1674 |
1675 | 在实现itheima-pack的loader功能时,同样也可以在加载每个模块时,根据rules的正则来匹配是否满足条件,如果满足条件则加载对应的loader函数并迭代调用
1676 |
1677 | depAnalyse()方法中获取到源码后,读取loader:
1678 |
1679 | ```js
1680 | let rules = this.config.module.rules
1681 | for (let i = rules.length - 1; i >= 0; i--) {
1682 | // console.log(rules[i])
1683 | let {test, use} = rules[i]
1684 | if (test.test(modulePath)) {
1685 | for (let j = use.length - 1; j >= 0; j--) {
1686 | let loaderPath = path.join(this.root, use[j])
1687 | let loader = require(loaderPath)
1688 | source = loader(source)
1689 | }
1690 | }
1691 | }
1692 | ```
1693 |
1694 | ## 自定义插件
1695 |
1696 | ### 学习目标
1697 |
1698 | 在学习给自己写的itheima-pack工具添加plugin功能之前,得先学习webpack中如何自定义plugin,所以学习步骤分为两大步:
1699 |
1700 | 1. 掌握自定义webpack的plugin
1701 | 2. 学习给itheima-pack添加plugin功能并写一个plugin
1702 |
1703 | > 插件接口可以帮助用户直接触及到编译过程(compilation process)。 插件可以将处理函数(handler)注册到编译过程中的不同事件点上运行的生命周期钩子函数上。 当执行每个钩子时, 插件能够完全访问到编译(compilation)的当前状态。
1704 |
1705 | 简单理解,自定义插件就是在webpack编译过程的生命周期钩子中,进行编码开发,实现一些功能。
1706 |
1707 | ### webpack插件的组成
1708 |
1709 | - 一个 JavaScript 命名函数。
1710 | - 在插件函数的 prototype 上定义一个 apply 方法。
1711 | - 指定一个绑定到 webpack 自身的事件钩子。
1712 | - 处理 webpack 内部实例的特定数据。
1713 | - 功能完成后调用 webpack 提供的回调。
1714 |
1715 | ### webpack的生命周期钩子
1716 |
1717 | | 钩子 | 作用 | 参数 | 类型 |
1718 | | :------------------: | :----------------------------------------------------------: | :----------------------------: | :---------------: |
1719 | | entryOption | 在处理了webpack选项的entry配置后调用 | context, entry | SyncBailHook |
1720 | | **afterPlugins** | 在初始化内部插件列表后调用。 | compiler | SyncHook |
1721 | | afterResolvers | Compiler初始化完毕后调用。 | compiler | SyncHook |
1722 | | environment | 在准备编译器环境时调用,在对配置文件中的插件进行初始化之后立即调用。 | 无 | SyncHook |
1723 | | afterEnvironment | 在environment钩子之后立即调用,当编译器环境设置完成时。 | 无 | SyncHook |
1724 | | **beforeRun** | 在运行Compiler之前调用。 | compiler | AsyncSeriesHook |
1725 | | **run** | Compiler开始工作时调用。 | compiler | AsyncSeriesHook |
1726 | | watchRun | 在新的编译被触发但在实际开始编译之前,在监视模式期间执行插件。 | compiler | AsyncSeriesHook |
1727 | | normalModuleFactory | NormalModuleFactory创建后调用。 | normalModuleFactory | SyncHook |
1728 | | contextModuleFactory | ContextModuleFactory创建后运行插件。 | contextModuleFactory | SyncHook |
1729 | | beforeCompile | 创建compilation参数后执行插件。 | compilationParams | AsyncSeriesHook |
1730 | | compile | beforeCompile在创建新编辑之前立即调用。 | compilationParams | SyncHook |
1731 | | thisCompilation | 在触发compilation事件之前,在初始化编译时调用。 | compilation,compilationParams | SyncHook |
1732 | | compilation | 创建compilation后运行插件。 | compilation,compilationParams | SyncHook |
1733 | | **make** | 在完成编译前调用。 | compilation | AsyncParallelHook |
1734 | | **afterCompile** | 在完成编译后调用。 | compilation | AsyncSeriesHook |
1735 | | **shouldEmit** | 在发射assets之前调用。应该返回一个告诉是否发射出去的布尔值。 | compilation | SyncBailHook |
1736 | | **emit** | 向assets目录发射assets时调用 | compilation | AsyncSeriesHook |
1737 | | **afterEmit** | 在将assets发送到输出目录后调用。 | compilation | AsyncSeriesHook |
1738 | | **done** | 编译完成后调用。 | stats | AsyncSeriesHook |
1739 | | failed | 如果编译失败,则调用。 | error | SyncHook |
1740 | | invalid | 在watching compilation失效时调用。 | fileName,changeTime | SyncHook |
1741 | | watchClose | 在watching compilation停止时调用。 | 无 | SyncHook |
1742 |
1743 | ### 实现一个简单的plugin
1744 |
1745 | `compiler.hooks.done`表示编译完成后调用的钩子,所以只需要在这个阶段注册时间,当打包完成会自动回调这个函数
1746 |
1747 | ```js
1748 | class HelloWorldPlugin {
1749 | apply(compiler) {
1750 | compiler.hooks.done.tap('Hello World Plugin', (stats) => {
1751 | console.log('Hello World!');
1752 | });
1753 | }
1754 | }
1755 |
1756 | module.exports = HelloWorldPlugin;
1757 | ```
1758 |
1759 | ### 实现一个html-webpack-plugin
1760 |
1761 | 使用html-webpack-plugin非常简单,而且功能非常好用,可以将指定的html模板复制一份输出到dist目录下,同时会自动引入bundle.js
1762 |
1763 | 如何自己实现?
1764 |
1765 | 1. 编写一个自定义插件,注册`afterEmit`钩子
1766 | 2. 根据创建对象时传入的template属性来读取html模板
1767 | 3. 使用工具分析HTML,推荐使用cheerio,可以直接使用jQuery api
1768 | 4. 循环遍历webpack打包的资源文件列表,如果有多个bundle就都打包进去(可以根据需求自己修改,因为可能有chunk,一般只引入第一个即可)
1769 | 5. 输出新生成的HTML字符串到dist目录中
1770 |
1771 | ```js
1772 | const path = require('path')
1773 | const fs = require('fs')
1774 | const cheerio = require('cheerio')
1775 | module.exports = class HTMLPlugin {
1776 | constructor(options) {
1777 | // 传入filename和template
1778 | this.options = options
1779 | }
1780 | apply(compiler) {
1781 | compiler.hooks.afterEmit.tap('HTMLPlugin', compilation => {
1782 | // 根据模板读取html文件内容
1783 | let result = fs.readFileSync(this.options.template, 'utf-8')
1784 | // 使用cheerio来分析HTML
1785 | let $ = cheerio.load(result)
1786 | // 创建script标签后插入HTML中
1787 | Object.keys(compilation.assets).forEach(item => $(``).appendTo('body'))
1788 | // 转换成新的HTML并写入到dist目录中
1789 | fs.writeFileSync(path.join(process.cwd(), 'dist', this.options.filename), $.html())
1790 | })
1791 | }
1792 | }
1793 | ```
1794 |
1795 | **Compiler和Compilation的区别**
1796 |
1797 | - **compiler 对象表示不变的webpack环境,是针对webpack的**
1798 | - **compilation 对象针对的是随时可变的项目文件,只要文件有改动,compilation就会被重新创建。**
1799 |
1800 | ### 在itheima-pack中添加plugin的功能
1801 |
1802 | #### tapable简介
1803 |
1804 | 在webpack内部实现事件流机制的核心就在于**tapable**,有了它就可以通过事件流的形式,将各个插件串联起来,tapable类似于node中的events库,核心原理也是**发布订阅模式**
1805 |
1806 | 基本用法如下
1807 |
1808 | 1. 定义钩子
1809 | 2. 使用者注册事件
1810 | 3. 在合适的阶段调用钩子,触发事件
1811 |
1812 | ```js
1813 | let { SyncHook } = require('tapable')
1814 | class Lesson {
1815 | constructor() {
1816 | this.hooks = {
1817 | html: new SyncHook(['name']),
1818 | css: new SyncHook(['name']),
1819 | js: new SyncHook(['name']),
1820 | react: new SyncHook(['name']),
1821 | }
1822 | }
1823 | study() {
1824 | console.log('开班啦,同学们好!')
1825 | console.log('开始学html啦,同学们好!')
1826 | this.hooks.html.call('小明')
1827 | console.log('开始学css啦,同学们好!')
1828 | this.hooks.css.call('小花')
1829 | console.log('开始学js啦,同学们好!')
1830 | this.hooks.js.call('小黑')
1831 | console.log('开始学react啦,同学们好!')
1832 | this.hooks.react.call('紫阳')
1833 | }
1834 | }
1835 |
1836 | let l = new Lesson()
1837 | l.hooks.html.tap('html', () => {
1838 | console.log('我要写个淘宝!!!挣他一个亿!')
1839 | })
1840 |
1841 | l.hooks.react.tap('react', (name) => {
1842 | console.log('我要用react构建一个属于自己的王国!' + name + '老师讲的真好!!!')
1843 | })
1844 | l.study()
1845 | ```
1846 |
1847 | 通过该案例可以看出,如果需要在学习的不同阶段,做出不同的事情,可以通过发布订阅模式来完成。而tapable可以帮我们很方便的实现发布订阅模式,同时还可以在调用时传入参数。
1848 |
1849 | 以上只是最基础的同步钩子演示,如果感兴趣,可以查阅官方文档,并练习对应的其他钩子,以下是tapable对外暴露的所有钩子:
1850 |
1851 | ```js
1852 | exports.Tapable = require("./Tapable");
1853 | exports.SyncHook = require("./SyncHook");
1854 | exports.SyncBailHook = require("./SyncBailHook");
1855 | exports.SyncWaterfallHook = require("./SyncWaterfallHook");
1856 | exports.SyncLoopHook = require("./SyncLoopHook");
1857 | exports.AsyncParallelHook = require("./AsyncParallelHook");
1858 | exports.AsyncParallelBailHook = require("./AsyncParallelBailHook");
1859 | exports.AsyncSeriesHook = require("./AsyncSeriesHook");
1860 | exports.AsyncSeriesBailHook = require("./AsyncSeriesBailHook");
1861 | exports.AsyncSeriesWaterfallHook = require("./AsyncSeriesWaterfallHook");
1862 | exports.HookMap = require("./HookMap");
1863 | exports.MultiHook = require("./MultiHook");
1864 | ```
1865 |
1866 | #### 利用tapable实现itheima-pack的plugin功能
1867 |
1868 | 在Compiler构造时,创建对应的钩子即可
1869 |
1870 | ```js
1871 | // Compiler的构造函数内部定义钩子
1872 | this.hooks = {
1873 | afterPlugins: new SyncHook(),
1874 | beforeRun: new SyncHook(),
1875 | run: new SyncHook(),
1876 | make: new SyncHook(),
1877 | afterCompile: new SyncHook(),
1878 | shouldEmit: new SyncHook(),
1879 | emit: new SyncHook(),
1880 | afterEmit: new SyncHook(['compilation']),
1881 | done: new SyncHook(),
1882 | }
1883 |
1884 | // 触发所有插件的apply方法,并传入Compiler对象
1885 | if (Array.isArray(this.config.plugins)) {
1886 | this.config.plugins.forEach(plugin => {
1887 | plugin.apply(this)
1888 | })
1889 | }
1890 | ```
1891 |
1892 | 在合适的时机调用对应钩子的call方法即可,如需传入参数,可以在对应的钩子中定义好需要传入的参数,call时直接传入
1893 |
1894 | 
1895 |
1896 | # 第6章 课程总结
1897 |
1898 | - webpack基础配置
1899 | - 安装:本地安装即可,无需全局安装
1900 | - 使用:CLI的方式或配置脚本使用配置文件
1901 | - 配置:
1902 | - 开发时工具:watch、dev-server、webpack-dev-middleware、sourceMap
1903 | - loaders:css-loader、style-loader、less-loader、sass-loader、url-loader、babel-loader、
1904 | - plugins:html-webpack-plugin、clean-webpack-plugin、copy-webpack-plugin、BannerPlugin
1905 | - webpack高级配置
1906 | - img标签资源处理
1907 | - 多页应用打包
1908 | - 第三方库的引入方式
1909 | - 区分配置文件打包
1910 | - 环境变量
1911 | - proxy
1912 | - HMR
1913 | - webpack性能优化
1914 | - webpack自带优化详解
1915 | - css优化
1916 | - 提取到单独文件
1917 | - 自动添加前缀
1918 | - 压缩注意事项
1919 | - js优化
1920 | - 代码分离:手动配置多入口、抽取公共代码、懒加载、SplitChunksPlugin参数详解
1921 | - noParse
1922 | - IgnorePlugin
1923 | - DllPlugin:将固定库抽取成动态链接库节省资源
1924 | - 多进程打包
1925 | - 浏览器缓存
1926 | - 打包分析
1927 | - Prefetching
1928 | - webpack原理
1929 | - 分析bundle文件
1930 | - 手写基础的webpack
1931 | - 利用AST完成代码转译
1932 | - 手写loader并给自己的webpack添加loader功能
1933 | - webpack中tapable的应用
1934 | - 手写plugin并给自己的webpack添加plugin功能
1935 |
1936 | 学习不是百米冲刺,而是一场马拉松,现在所学只是起点,更多的是需要大家找到学习方法,不断的学习提升自己,一起加油!
--------------------------------------------------------------------------------