├── 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 | 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 | 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 | 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 | 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 | ![1556458624028](./assets/webpack.png) 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 | ![跨域](./assets/跨域.png) 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 | ![解决跨域](./assets/解决跨域.png) 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 | ![main](./assets/main.bundle.js.png) 976 | 977 | ![other](./assets/other.bundle.js.png) 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 | ![1558771916946](assets/1558771916946.png) 1003 | 1004 | 4. 查看`vendors~main~other.bundle.js`,其实就是把都用到的jQuery打包到了一个单独的js中 1005 | 1006 | ![1558772012664](assets/1558772012664.png) 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 | ![A diagram showing the flow between HappyPack's components](assets/HappyPack_Workflow.png) 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 | ![1559811338075](assets/1559811338075.png) 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 | ![1561174288710](./assets/1561174288710.png) 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 | ![1561895540321](./assets/1561895540321.png) 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 | 学习不是百米冲刺,而是一场马拉松,现在所学只是起点,更多的是需要大家找到学习方法,不断的学习提升自己,一起加油! --------------------------------------------------------------------------------