首先我们要做的第一件事:需要先生成一个package.json
npm init -y
安装使用webpack所需要的依赖
这里你可以使用npm(原版)或者cnpm(国内的镜像)安装
cnpm i -D webpack webpack-cli typescript ts-loader
i:install缩写-D: 开发依赖,完整写法是saveDevwebpack:打包工具的核心代码webpack-cli: 是我们webpack的一个命令行工具,装完这个就可以使用webpack命令行去使用webpack工具了typescript:ts的核心包ts-loader: 通过这个可以将我们的webpack和typescript进行一个整合,让它们变成一个一体的
在自己创建的package.json里面出现:
"devDependencies": {"ts-loader": "^9.2.6","typescript": "^4.5.5","webpack": "^5.68.0","webpack-cli": "^4.9.2"}
就说明安装成功了
接下来我们就要编写一个webpack的一个配置文件
webpack.config.js(这是默认名字)
//写我们webpack的一些配置信息//1.引入一个包const path = require('path');//就相当于是nodejs里面的一个模块,这个包主要为我们拼接一个路径//正式的编写一个配置信息//webpack所有的配置信息都应该写在module.exports中module.exports = {//指定入口文件(通常有一个src目录,在这个文件下创建一个index.ts作为入口文件)entry: "./src/index.ts",//作为主文件/入口文件//打包:就是把我们的文件输出到一个指定的位置//指定打包文件所在的目录output: {//path:指定我们打包后的目录// path: "./dist",//或者path: path.resolve(__dirname,'dist'),//filename:是我们打包后文件的名字filename: "bundle.js"}};
这是我们的入口和出口
但是我们的ts文件是需要进行编译的,也就是我们需要把ts编译成js,那它要如何去编译呢?
这个时候我们就需要我的module:
//指定webpack打包时要使用的模块module: {//指定要加载的规则rules:[{//test指定我们规则生效的文件test: /\.ts$/,//用正则表达式.ts结尾: \.:进行转义 这就表示去匹配所有的以ts结尾的文件//要使用的loaderuse: 'ts-loader',//连起来的意思就是:我用ts-loader去处理以ts结尾的文件//要排除的文件exclude: /node-modules/,//一般排除node_modules}]}
这样我们ts-loader就已经处理完了
webpack基础的完整配置:
//写我们webpack的一些配置信息//1.引入一个包const path = require('path');//就相当于是nodejs里面的一个模块,这个包主要为我们拼接一个路径//正式的编写一个配置信息//webpack所有的配置信息都应该写在module.exports中module.exports = {//指定入口文件(通常有一个src目录,在这个文件下创建一个index.ts作为入口文件)entry: "./src/index.ts",//作为主文件/入口文件//打包:就是把我们的文件输出到一个指定的位置//指定打包文件所在的目录output: {//path:指定我们打包后的目录// path: "./dist",//或者path: path.resolve(__dirname,'dist'),//filename:是我们打包后文件的名字filename: "bundle.js"},//指定webpack打包时要使用的模块module: {//指定要加载的规则rules:[{//test指定我们规则生效的文件test: /\.ts$/,//用正则表达式.ts结尾: \.:进行转义 这就表示去匹配所有的以ts结尾的文件//要使用的loaderuse: 'ts-loader',//连起来的意思就是:我用ts-loader去处理以ts结尾的文件//要排除的文件exclude: /node-modules/,//一般排除node_modules}]}};
通过这样的一个配置,我们webpack.config.js的一个最基本的配置就写完了,这时候我们的webpack就可以去使用了。但是我们只配置webpack是不行的
我们./src这一块要进行ts文件进行编译,所以我们还要指定一个配置文件进行ts的一个编译规范
创建
tsconfig.json
{"compilerOptions": {"target": "ES6","module": "ES6","strict": true}}
这样子写,我们所有的配置就基本完成了
最后一件事
不是想打包嘛
package.json(里面加一个
build)
{"name": "webpack_ts_one","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","build": "webpack"},"author": "","license": "ISC","devDependencies": {"ts-loader": "^9.2.6","typescript": "^4.5.5","webpack": "^5.68.0","webpack-cli": "^4.9.2"}}
我们可以通过build命令来直接执行我们的webpack
我们可以直接通过
npm run build
去直接执行我们的webpack,用webpack来对我们的项目进行打包
什么都没有?那我们在src/index.ts中写入:
function sum(a:number,b:number):number{return a + b;}console.log(sum(123,456))
进行编译
以下就都是webpack的知识了
以上的最最最基本的webpack实现了js,但是我们要运行的话最终都是要放到网页里面去运行的
所以运行这个文件我们还要创建一个html文件
其实我们可以直接
创建index.html
<html><head><meta charset="utf-8"><title>Title</title></head><body><script></script></body></html>
但是,我不想用这种方式,为什么?
麻烦,因为这种方式是我纯手动的去创建和引入这个文件。当我文件发生了变化了,现在我只引入了一个js文件,那我以后引入了三js或者引入多个css文件,这个时候发生变化,我需要手动的一个一个的去改
所以这个时候我就想喜欢,我们的html文件是webpack给我们自动创建的,然后创建完了以后这个网页引入哪些资源都是由它根据我们项目的实际情况做出的调整。
这个时候我们就要用到webpack的一个插件:html-webpack-plugin
cnpm i -D html-webpack-plugin
下载完后就要进入我们的webpack.config.js里,要对插件进行配置
//首先我们要引入html插件const HTMLWebpackPlugin = require('html-webpack-plugin');//我们需要插件生效//正式的编写一个配置信息//webpack所有的配置信息都应该写在module.exports中module.exports = {//指定入口文件(通常有一个src目录,在这个文件下创建一个index.ts作为入口文件)entry: "./src/index.ts",//作为主文件/入口文件//打包:就是把我们的文件输出到一个指定的位置//指定打包文件所在的目录output: {//path:指定我们打包后的目录// path: "./dist",//或者path: path.resolve(__dirname,'dist'),//filename:是我们打包后文件的名字filename: "bundle.js"},//指定webpack打包时要使用的模块module: {//指定要加载的规则rules:[{//test指定我们规则生效的文件test: /\.ts$/,//用正则表达式.ts结尾: \.:进行转义 这就表示去匹配所有的以ts结尾的文件//要使用的loaderuse: 'ts-loader',//连起来的意思就是:我用ts-loader去处理以ts结尾的文件//要排除的文件exclude: /node-modules/,//一般排除node_modules}]},//引入webpack插件plugins: [new HTMLWebpackPlugin(),//html-webpack-plugin插件就在我们的webpack中生效了]};
执行我们的
npm run build
我想修改标签:
plugins: [new HTMLWebpackPlugin({title: "my ts learn one--webpack"}),]
是可以自定义了,但是我不能一个一个的自定义,因为我们的网页可能会比较复杂。那还有一招:
你希望你的网页有一个基本的结构的,那指定一个
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>my ts learn one--webpack</title></head><body><div id="box1">我是一个div</div></body></html>
想写什么就写什么,这个就设置我们的模板,根据我们的模板去生成它的html
webpack.config.js
plugins: [new HTMLWebpackPlugin({template: './public/index.html'}),]
也就是说我们只需要提供一个模板,剩下的都交给webpack去自动完成
我们还面临的一个问题
就是我们文件的一个浏览的问题
也就是我们的服务器要与我们的项目是有关联的,当我的项目改了以后,给我自动的重新构建,构建完了以后浏览器自动的刷新让我们看到结果,这样我们开发起来就很舒服。
所以:
第二个插件
我们webpack的开发服务器
cnpm i -D webpack-dev-server
就相当于在项目内部安装了一台服务器。这个服务器对于我们的webpack是有关联的,它可以根据你的项目改变自动的去刷新。
装完后,要去package.json里面安装一个命令:
package.json
{"name": "webpack_ts_one","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","start": "webpack serve --open",//添加这条(粘贴的话最好取消这注释)"build": "webpack"},"author": "","license": "ISC","devDependencies": {"html-webpack-plugin": "^5.5.0","ts-loader": "^9.2.6","typescript": "^4.5.5","webpack": "^5.68.0","webpack-cli": "^4.9.2","webpack-dev-server": "^4.7.4"}}
执行
npm start
会对我们的文件进行监视
大体上的插件我们就说完了,还有俩个小的问题
我们编译的时候是不会删除原来的文件,实际上是我们生成的文件,把原来的文件给替换掉了
第三个插件
实现的功能:每一次编译前先把dist目录给你自动清空,然后把新文件给它放进去,这样就可以确保我们**dist**里面的文件都是当前最新的,避免有旧文件的情况。这个文件跟我们的**html-webpak-plugin**差不多
cnpm i -D clean-webpack-plugin
作用: 就是来清除我们这个**dist**这个目录
用法:
//引入clean插件const {CleanWebpackPlugin} = require('clean-webpack-plugin')module.exports = {entry: "./src/index.ts",output:{path: "",filename: "",},module:{test: "",use: "",exclude: [],},plugins:[new HTMLWebpackPlugin({template: "路径"}),new CleanWebpackPlugin(),]}
最后一个问题
添加一个m1.ts:
export const hi:string = '你好';//向外暴露hi变量
index.ts去引入这一个变量
import {hi} from './m1';function sum(a:number,b:number):number{return a + b;}console.log(sum(123,456))function hello():string{console.log('hello')return 'hello';}hello()console.log(hi)
会报错。为什么报错?
因为我们现在引入m1,m1是一个模块,它的扩展名是
ts,在我们的webpack中他不知道你这个ts是可以作为模块使用的,也就是说它不知道你这个m1文件可以被引入,这个时候你就要做一个配置来告诉webpack哪些文件可以作为模块可以被引入和使用webpack.config.js
module.exports = {entry: "./src/index.ts",output:{path: "",filename: "",},module:{test: "",use: "",exclude: [],},plugins:[new HTMLWebpackPlugin({template: "路径"}),],//用来设置引用模块resolve: {//告诉它:凡事以ts和js结尾的扩展名的文件就都可以作为模块使用extensions: ['.ts','.js']}}
其实我们这里还有一个兼容性问题
查看生成的bundle.js:
(()=>{"use strict";console.log(579),console.log("hello"),console.log("你好")})();
这些都是新版的语法,那对于老版本的浏览器就不支持了,所以我们还要引入一个工具,让这个工具帮助我们去改我们的代码,把我们的代码改成我们不同的版本以兼容更多的浏览器
以上就把我们webpack初步配置完成了
但是真正到了实际开发中,这样还不够,我们还需要在webpack中引入一个插件
它其实可以跟webapck联合使用替我们去完成一些工作,什么样的工作?
它的工作有一部分与我们的ts有点像,就是我们去写代码的时候有不同的标准:有es5 es6 es2017,比如我是用最新的es2022去写的,但是我们的代码要运行到IE浏览器里,那这个时候就产生了一个兼容性的问题,因为IE浏览器不支持最新的标准,那它怎么去执行?
必须在写完代码以后,把它转换为旧版的,比如转换成
ES5这样就可以在IE浏览器里面可以正常的去执行。
这个功能我们ts也有,ts写完代码不是有target选项,去指定我们这个ts代码编译的版本。但是有些功能是ts里面不具备的: 就是我想刚才那些转换ts里面能做的转换简单的只是做一些语法的转换,但是对于一些复杂的功能,ES6里面新增的一些技术,这些东西光光仅仅通过这些语法的转换,实际上是不过去的,所以我们需要通过工具去解决,
这个工具其实是叫做babel
它的作用主要就这么几个:
- 1.新语法转换为旧语法
- 2.它可以把我们新的技术以及新的类、新的对象在旧浏览器里面不支持的,它可以通过一些方式,让它支持
为了让我们的代码有更好的兼容性,更好的这么一个使用的这么一个广路,在不同的浏览器中去使用,其实我们在开发过程中必须要安装一个babel来帮我们去解决这么一个兼容性问题。
这个babel也是需要和我们这个webpack一起结合使用。
使用流程
1.下载安装
cnpm i -D @babel/core @babel/preset-env babel-loader core-js
@babel/core:bable核心的一个工具@babel/preset-env: 预先设置的env:预先设置的环境: 这里就预置了不同浏览器的环境,你是什么样的环境,就预置了什么样的代码babel-loader: loader都是属于是(这里是bable)和webpack做一个结合的这么一个工具core-js: 它是一个js的一个运行环境或者说是模拟js运行环境的这么一个代码。好处就是可以让我们老版本的浏览器用到新标准的一些技术。但是core-js本身包含的东西比较多,我们用的时候不需要把整个加载进来,所以会有一个配置选项,然我们按需加载。
查看是否安装完毕(package.json)
{"name": "webpack_ts_one","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","start": "webpack serve --open","build": "webpack"},"author": "","license": "ISC","devDependencies": {"@babel/core": "^7.17.0","@babel/preset-env": "^7.16.11","babel-loader": "^8.2.3","core-js": "^3.21.0","html-webpack-plugin": "^5.5.0","ts-loader": "^9.2.6","typescript": "^4.5.5","webpack": "^5.68.0","webpack-cli": "^4.9.2","webpack-dev-server": "^4.7.4"}}
2.做配置(修改webpack.config.js文件)应该不是说插件而是说加了一个新的加载器进来
修改
module对我们test里的.ts去生效
//写我们webpack的一些配置信息//1.引入一个包const path = require('path');//就相当于是nodejs里面的一个模块,这个包主要为我们拼接一个路径const HTMLWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: "./src/index.ts",//作为主文件/入口文件output: {path: path.resolve(__dirname,'dist'),filename: "bundle.js"},module: {rules:[{//test指定我们规则生效的文件test: /\.ts$/,use: [//这个加载器是从后往前执行,所以谁写在后面谁先执行'bable-loader',//然后再用bable把新版本的js转换成旧版的js'ts-loader',//先把我们的ts代码转换成js],exclude: /node-modules/,}]},plugins: [new HTMLWebpackPlugin({template: './public/index.html'}),],resolve: {extensions: ['.ts','.js']}};
这样在use里面写babel-loader就直接只包含一个加载器。实际上babel包含着一些有些复杂的配置信息,所以这个配置我们要写的比较复杂一些。所以我们要写一个对象的形式:
use: [//这个加载器是从后往前执行,所以谁写在后面谁先执行{},//然后再用bable把新版本的js转换成旧版的js'ts-loader',//先把我们的ts代码转换成js],
配置信息多,就用复杂的(对象写法);配置信息少,就用简单的(字符串学法)根据实际情况写
先不写
index.ts
...const obj = {name: '我',age: 18};console.log(obj)obj.age = 18;console.log(obj)
npm run build
查看bundle.js
(()=>{"use strict";console.log(579),console.log("hello"),console.log("你好");const o={name:"我",age:18};console.log(o),o.age=18,console.log(o)})();
就看变量const o实际上就是转换成了ES6的代码了,所以不用babel整的还是ES6的版本
配置babel:
webpack.config.js
const path = require('path');const HTMLWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: "./src/index.ts",//作为主文件/入口文件output: {path: path.resolve(__dirname,'dist'),filename: "bundle.js"},module: {rules:[{test: /\.ts$/,use: [//这个加载器是从后往前执行,所以谁写在后面谁先执行//配置babel{//指定加载器loader: "babel-loader",//设置我们的babeloptions: {//设置预定义的环境presets: [[//指定我们环境的插件"@babel/preset-env",//配置信息(整体是一个对象){//指定目标浏览器targets: {//我的代码要运行在哪个浏览器里面//浏览器的版本"chrome": "88",//我的要兼容到浏览器88},//指定croejs版本"croejs": "3",//我们要用哪个版本的js//使用corejs的方式"useBuiltIns": "usage",//usage:按需加载}]]}},//然后再用bable把新版本的js转换成旧版的js'ts-loader',//先把我们的ts代码转换成js],//要排除的文件exclude: /node-modules/,}]},//引入webpack插件plugins: [new HTMLWebpackPlugin({template: './public/index.html'}),],resolve: {extensions: ['.ts','.js']}};
重新打包
npm run build
看那个o对象还是不是const定义的了
其实不会发生变化,还是const,为什么?
我们兼容的是
chrome88这是比较新的浏览器了,它对ES6的支持非常好,所以这个时候你兼容的是chrome88,const88是支持的,所以它没有给你转
如果这么写:
module: {rules:[{test: /\.ts$/,use: [//这个加载器是从后往前执行,所以谁写在后面谁先执行//配置babel{//指定加载器loader: "babel-loader",//设置我们的babeloptions: {//设置预定义的环境presets: [[//指定我们环境的插件"@babel/preset-env",//配置信息(整体是一个对象){//指定目标浏览器targets: {//我的代码要运行在哪个浏览器里面//浏览器的版本"chrome": "58",//我的要兼容到浏览器88"ie": "11",//表示我现在的代码要兼容这个俩个浏览器的},//指定croejs版本"croejs": "3",//我们要用哪个版本的js//使用corejs的方式"useBuiltIns": "usage",//usage:按需加载}]]}},//然后再用bable把新版本的js转换成旧版的js'ts-loader',//先把我们的ts代码转换成js],//要排除的文件exclude: /node-modules/,}]}
ie11肯定是不支持const版本的
编译流程是这样的: **ts**文件先去找**ts-loader**,先转换成**js**,然后**js**再找我们的**babel**去转换成**老版本的js**
index.ts
console.log(Pomise())
会加一堆内容,为什么会加这么多的内容?
这一堆代码就是core-js的代码。core-js发现你用
Promise,你又想兼容到ie11,而ie11又不支持Promise,那怎么办: 它给你引入了,它自己的版本的一个Promise,让ie11去使用
但是加完,**Promise**不一定就在**ie11**里面能用了
如果webpack打包生成的还是箭头函数(老版本ie不支持箭头函数),一定要修改,怎么做?
module.exports = {entry: "./src/index.ts",//作为主文件/入口文件output: {//path:指定我们打包后的目录// path: "./dist",//或者path: path.resolve(__dirname,'dist'),//filename:是我们打包后文件的名字filename: "bundle.js",//这个是配置我们打包的环境environment:{arrowFunction: false,//告诉webpack不使用我们的箭头函数}},...}
