返回章节目录
目录
1.关于开发环境
2.git介绍
3.关于chrome调试和抓包
4.关于电脑调试手机网页
5.webpack-搭建环境
6.webpack-babel(ES6的东西转换成ES5)
7.webpack-ES6-Module(ES6的模块化)
单个导出
一起导出
8.webpack-配置生产环境
面试官想通过开发环境了解候选人的实际工作情况,而开发环境的工具能体现工作产出的效率,这些问题会以聊天形式为主,不会问具体的问题。
在这里1、2、3、4点我都是只是概述总结,没有细讲,因为每个都是长篇大论而且网上搜得到
5、6、7、8是从0到1搭建webpack环境并且运行,如果有一点webpack经历,这应该是一个很好的复习
关于git,不讲命令,由于篇幅太大,我另外写了一篇,方便跳转过去看,链接如下
Git从开发到上线中那些事和个人体会
面试不考,却是程序员写代码的必备技能,讲起来是一个非常长的篇幅,网上能搜到很多
关于chrome调试,自己搜一下进行学习
关于抓包
移动端的h5页面查看网络请求的时候,需要用工具抓包
windows一般用fiddler,Mac OS一般用charles,我个人是用的charles
问题来了,怎么学习呢?搜索“fiddler如何使用”之类的,或者“charles如何使用”之类的。
当usb连接之后,开始准备抓包的时候,有强校验的app是无法运行的,会报网络环境异常之类的错误
面试不考,仍然是内功技能。讲起来是一个非常长的篇幅,网上能搜到很多
如果利用chrome浏览器,需要,可以搜索"chrome手机调试",调试的时候可以看到网页源代码和手机页面,总体来讲我个人认为需要体验不太好也太麻烦,万一公司不让呢?需要申请权限之类的呢?
如果利用firefox浏览器,不需要,可以搜索"firefox手机调试",但是调试的时候只看得到网页源代码,无法看到手机页面,所以只能从选中代码去选中界面中的元素,而无法直接在响应式设计界面中点击跳转到对应代码。
这里和大家说一下,避免浪费时间去踩坑,我是浪费时间去踩坑了的。
接下来就是简单的demo从0--1的过程了。
先自己创建一个工程目录,比如webpack-demo,然后进去到webpack-demo目录
查看是否安装node
node -v
有版本号就是安装好了
接下来npm init -y
就自动创建了package.json ,当然也可以去掉-y,会出现下面提示,一路回车就可以,达到和-y一样的效果
执行完之后webpack-demo目录中多了一个package.json文件
接着执行命令npm install webpack webpack-cli -D
这个可能会出错,可以加上淘宝镜像去代理,这和cnpm安装一样的效果,淘宝镜像目录https://npm.taobao.org/,则运行
npm install webpack webpack-cli -D --registry=https://registry.npm.taobao.org
但是仍然有可能报错,不知道大家是不是和我一样执行的时候会如下报错
No receipt for 'com.apple.pkg.CLTools_Executables' found at '/'.
No receipt for 'com.apple.pkg.DeveloperToolsCLILeo' found at '/'.
No receipt for 'com.apple.pkg.DeveloperToolsCLI' found at '/'.
gyp: No Xcode or CLT version detected!
gyp ERR! configure error
gyp ERR! stack Error: `gyp` failed with exit code: 1
我就下载安装了一个XCode就好了,可以参见这里的报错经历
接着用vscode打开目录如下
在这里目webpack-demo目录下创建src目录
接着在src里面新建index.js
console.log("this is index js")
然后在webpack-demo目录新建webpack.config.js,这就是webpack默认的配置文件的名字
在webpack.config.js内容如下:
const path = require('path')
module.exports = {
mode: 'development', // production
entry: path.join(__dirname, 'src', 'index.js'),//__dirname就是当前目录(同一套代码不同环境可能当前环境路径字符串不一样,__dirname能统一表示)
//拼接src再拼接index.js,就能找到整个文件的入口
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist')
}
}
接着准备运行了,我们来到package.json,在scripts里面加上"build": "webpack",如下:
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
/*"webpack --config webpack.config.js"如果webpack配置文件名字改了,那么就在这里指定修改*/
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10"
}
}
webpack打包的时候默认配置文件是webpack.config.js,所以不用指定webpack --config webpack.config.js,除非配置文件是其它名字
接着我们执行命令,npm run build,我们指定了build为webpack,所以等同于你执行npm run webpack
只要我们运行的是npm脚本(就是scripts里面的),打包的时候就会显示你的当前目录和你的脚本命令,这里是webpack,说明你的"build"对应"webpack",只要打包的内容不变,Hash值就不会变。Version显示你的webpack版本,Time是你的打包花费的时间。Built at是你的打包日期。Asset地下显示的bundle.js是生成的打包文件名,3.8KB,Chunks是js文件对应的id,Chunks Names代表每一个js对应的名字,这里为什么是main,是因为你的配置文件webpack.config.js里的
entry: path.join(__dirname, 'src', 'index.js')其实是一种简写,默认如下
entry: { main: path.join(__dirname, 'src', 'index.js')},你可以把这个的main换成main2试试,如果你的Chunks就变成main2,则显示Entrypoint main2 = bundle.js
[./src/index.js] 31 byte {main2} [built]表示打包需要的js文件
这里面包含了index.js的内容
webpack打包的时候要考虑自己的打包方案,所以上面的内容看到各种modulexxx
webpack可以兼容模块化的方案,所以会加上很多模块化的代码
在src下面新建index.html
webpack演示
webpack demo
接着还得安装一个解析html的插件html-webpack-plugin
npm install html-webpack-plugin -D --registry=https://registry.npm.taobao.org
继续安装一个能启动服务的插件webpack-dev-server
npm install webpack-dev-server -D --registry=https://registry.npm.taobao.org
接下来要去webpack.config.js去加上插件和开启本地服务的配置
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引进解析html的插件
module.exports = {
mode: 'development', // production
entry: path.join(__dirname, 'src', 'index.js'),//__dirname就是当前目录(同一套代码不同环境可能当前环境路径字符串不一样,__dirname能统一表示)
//拼接src再拼接index.js,就能找到整个文件的入口
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin(
{
template: path.join(__dirname, 'src', 'index.html'),
filename: 'index.html' // 打包后产出的文件名
}
)
],
// 启动本地服务
devServer: {
port: 3000,
// 启动服务器的目录
contentBase: path.join(__dirname, 'dist')
}
}
然后在package.json的scripts里面加上一句"dev": "webpack-dev-server"
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"dev": "webpack-dev-server"
},
"author": "",
"license": "ISC",
"devDependencies": {
"html-webpack-plugin": "^3.2.0",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.2"
}
}
然后命令行执行npm run dev
执行之后看到服务器开起来了,端口3000 ,运行结果如下,就是index.html的内容
有人会奇怪了,我这里还没有打包npm run build,没在dist目录看到文件,怎么就可以访问了?
过程描述一下就是:最后新增了"dev":"webpack-dev-server"之后,并没有去npm run build而是直接去npm run dev,在dist打包目录下只有bundle.js,没有就index.html,但是居然运行成功了,能访问index.html,why???
webpack-dev-server 生成 bundle.js 和 index.html ,放在内存中,直接作为 server 的返回(因为的这里是本地服务器),而不是生成两个文件。
细心的同学观察到了,开启服务器之后,我们只要一保存就马上编译,可以访问最新内容,这是因为webpack 结合 webpack-dev-server 会自动启动了“自动刷新”功能。
相当于是ES6的编译,将ES6转换成ES5语法,因为有的浏览器太落后,ES6语法无法识别
比如刚刚上面的例子,我们在index.js中修改一下代码
const sum = (a, b) => {
return a + b
}
const res = sum(10, 20)
console.log(res)
接着访问localhost:3000/bundle.js
看到打包后还是ES6代码如下
我们需要转换成ES5的代码,应该如何操作呢?
babel就是js的高级语法向低级语法转变的工具,babel可以提供插件给webpack用
执行命令npm i @babel/core @babel/preset-env babel-loader
i就是install的简写,@就是组,@babel/core表示安装bable组里面的core模块,env是babel的配置插件集合,babel-loader就是给webpack用的一个插件
接着在webpack-demo目录下新建.babelrc文件(和webpack.config.js在同一目录)
{
"presets": [
"@babel/preset-env"
]
}
接着修改webpack.config.js,主要是加上module模块
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引进解析html的插件
module.exports = {
mode: 'development', // production
entry: path.join(__dirname, 'src', 'index.js'),//__dirname就是当前目录(同一套代码不同环境可能当前环境路径字符串不一样,__dirname能统一表示)
//拼接src再拼接index.js,就能找到整个文件的入口
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist')
},
module: {
rules: [
{ // 对js解析,只要以js结尾的,就都走一个loader转义
test: /\.js$/,
loader: ['babel-loader'], // 只是babel-loader提供给webpack的一个插件,真正做转义的还是@babel/core,所以要加上.babelrc的一个配置
include: path.join(__dirname, 'src'), // 包含哪些目录需要经过这个loader的转义
exclude: /node_modules/ // 这个已经转义过了没必要再次包含
}
]
},
plugins: [
new HtmlWebpackPlugin(
{
template: path.join(__dirname, 'src', 'index.html'),
filename: 'index.html' // 打包后产出的文件名
}
)
],
// 启动本地服务
devServer: {
port: 3000,
// 启动服务器的目录
contentBase: path.join(__dirname, 'dist')
}
}
module模块就是针对不同模块做不通的解析
最后保存,执行npm run dev,再来访问localhost:3000/bundle.js
看看这个sum函数,我们写的ES6语法已经被转义为ES5语法了
那用我们之前讲之前的例子试试,讲index.js改为
// 类
class Student {
constructor(name, number) {
this.name = name // 这个对象里新增一个name赋值为传进来的name
this.number = number
// this.gender = 'male'
}
sayHi() {
console.log(
`姓名 ${this.name} ,学号 ${this.number}`
)
}
}
// 通过类 new 对象/实例
const xialuo = new Student('夏洛', 100)
console.log(xialuo.name)
console.log(xialuo.number)
xialuo.sayHi()
const madongmei = new Student('马冬梅', 101)
console.log(madongmei.name)
console.log(madongmei.number)
madongmei.sayHi()
保存后再来访问localhost:3000/bundle.js,结果如下,ES6的字符串写法和class都变了,语法降级
继续接着上面讲
我们在src里面新建a.js,去提供函数和变量,让index.js去使用,用模块化就是想用一个导出导入的过程
a.js(这里讲一个一个导出)
// 向外提供函数
export function fn() {
console.log('fn')
}
// 向外提供变量
export const name = 'b'
// 向外提供对象
export const obj = {
name: 'zhangsan'
}
index.js
import {fn, name, obj} from './a' // 类似于解构赋值
fn()
console.log(name)
console.log(obj)
运行结果
a.js
function fn() {
console.log('fn')
}
const name = 'b'
const obj = {
name: 'lisi'
}
export {
fn,
name,
obj
} // 注意,这是ES6的写法,不只局限于模块化,如果key和value一样,简写一个就行了,ES5只能用key-value形式来写
// ES5写法如下
/*export {
fn:fn,
name:name,
obj:obj
}*/
index.js不变
运行结果
又或者a.js改为如下,导出加了一个defalut,就没法和解构赋值一样来导入了
function fn() {
console.log('fn')
}
const name = 'b'
const obj = {
name: 'lisi'
}
export default {
fn,
name,
obj
} // 注意,这是ES6的写法,不只局限于模块化,如果key和value一样,简写一个就行了,ES5只能用key-value形式来写
// ES5写法如下
/*export {
fn:fn,
name:name,
obj:obj
}*/
index.js
import A from './a' // 导入的default对象给它一个名字叫A
A.fn()
console.log(A.name)
console.log(A.obj)
运行结果不变
现在的webpack.config.js是开发环境的webpack配置,但是不能直接上线,体积又大运行又慢,接下来我们来看看怎么配置一个生产环境的打包
我们在当前目录新建一个生产环境的配置文件webpack.prod.js,prod就是production的简写
webpack.prod.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引进解析html的插件
module.exports = {
mode: 'production',
entry: path.join(__dirname, 'src', 'index.js'),//__dirname就是当前目录(同一套代码不同环境可能当前环境路径字符串不一样,__dirname能统一表示)
//拼接src再拼接index.js,就能找到整个文件的入口
output: { // [contenthash]是根据代码内容算出的hash值来追加命名,代码不变命名就不变
filename: 'bundle.[contenthash].js',
path: path.join(__dirname, 'dist')
},
module: {
rules: [
{ // 对js解析,只要以js结尾的,就都走一个loader转义
test: /\.js$/,
loader: ['babel-loader'], // 只是babel-loader提供给webpack的一个插件,真正做转义的还是@babel/core,所以要加上.babelrc的一个配置
include: path.join(__dirname, 'src'), // 包含哪些目录需要经过这个loader的转义
exclude: /node_modules/ // 这个已经转义过了没必要再次包含
}
]
},
plugins: [
new HtmlWebpackPlugin(
{
template: path.join(__dirname, 'src', 'index.html'),
filename: 'index.html' // 打包后产出的文件名
}
)
],
// // 启动本地服务
// devServer: { // 要上线的代码,本地服务不需要
// port: 3000,
// // 启动服务器的目录
// contentBase: path.join(__dirname, 'dist')
// }
}
这里的mode是production,如果不写mode,会报警告提示,默认是production,打包出来的文件会被压缩成一行,如果写成development,打包出来的文件代码就不会被压缩。
接着我们需要去package.json去修改"build",因为"build"的value还是"webpack",默认运行的开发环境配置webpack.config.js,它会去启动我们写的服务devServer,那我们怎么办呢?
来改一改package.json,我们上面讲了,"build" : "webpack"就是"build" : "webpack --config webpack.config.js",而现在我们需要指定生产环境的配置,所以需要变成"build" : "webpack --config webpack.prod.js"
package.json
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.prod.js",
"dev": "webpack-dev-server"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/preset-env": "^7.8.4",
"babel-loader": "^8.0.6",
"html-webpack-plugin": "^3.2.0",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.2"
},
"dependencies": {}
}
我们先删掉dist目录,防止之前的结果干扰观察,接着再次执行npm run build,现在运行的就是生产环境的配置webpack.prod.js了,我们来看看dist里面是什么
bundle.hash值.js,就是我们刚刚配置的[contenthash],从打包的log也能看到,至于为什么要这么写,我们在下一章讲性能优化的时候再说,简单讲,为了页面运行的更快
我们可以看到bundle.hash值.js的内容都是经过压缩的,压缩后的代码体积又小运行又快,下载也快,所以生产环境必须单独配置。
关注、留言,我们一起学习。
===============Talk is cheap, show me the code================