webpack5

为什么有webpack?

web1.0阶段,还没有明确前端岗位,主要职责是编写静态页面,用Js来进行表单验证或动画效果。为了在页面上动态填充数据,后面也出现了php、jsp这种开发模式。

web2.0阶段,伴随ajax的诞生,不止负责展示界面,还能管理数据、和用户进行交互,这就诞生了jquery这样的前端库。

web3.0阶段,大前端开发/现代前端开发,前端工作变得多样化和复杂化,不止pc端、移动端、小程序这样的开发。事情多,流程复杂,就会出现问题。比如当前用模块开发,但是不同浏览器对模块化的支持不一样,而且模块化本身存在多种规范。

同时在编码中为了提高开发效率,还会使用es6+、ts、less\sass来编写,这些浏览器无法处理。

之后在整个开发过程中,我们希望在文件中实现实时监听,当内容出现修改和变更后,可以第一时间在浏览器看到修改后的内容。

在代码部署之前,对资源进行合并、压缩、优化处理。

所以我们需要webpack实现项目工程化。

webpack功能

打包:将不同类型的资源按模块处理,并打包

静态:打包后最终产出静态资源。

模块:webpack支持不同规范的模块化开发。比如es6 module,commonJS

为什么需要loader

在使用webpack中,它不是所有文件都能当模块来使用。所以需要loader进行转换,推荐用配置文件方式。

注意:loader从右到左,从上往下的匹配

browserslist

可以理解成去"Can I use" usage table网站上找到符合条件的浏览器版本信息,然后后续根据这些内容做兼容。

方法一:在src下建一个browserslistrc文件,把命令输入进去

方法二:在package.json里面写browserslist配置

 然后输入npx browserslist就可以看到结果了:

 postcss

postcss是什么?

利用js转换css样式的工具。主要用这个工具做一些兼容性处理。

安装postcss-cli的目的:为了在终端能使用postcss

autoprefixer可以对样式属性做一个前缀的添加(需要安装)

eg:输入

npx postcss --use autoprefixer -o ret.css ./src/css/test.css

顺序问题:

从右往左分别是 less-loader、postcss-loader、css-loader、style-loader

postcss-preset-env是什么?

预设,看做一个插件集合。(autoprefixer包含在postcss-preset-env里)

用法:比如把#12345678(前6位是颜色,7 8位是透明度)做一个兼容

 先安装,然后plugins里引入,然后就会把这样的color

 兼容成rgba的颜色

 importLoaders属性

例子:在login.css中引入test.css

 

 npm run build

发现只有color做了兼容,引入的test.css没有做兼容。

原因:

login.css被匹配到之后postcss-loader进行工作,基于上面代码,postcss-loader拿到login.css代码之后,将代码交给css-loader。css-loader可以处理@import /url 语句,这时候css-loader拿到test.css文件,但不会回头去找postcss-loader 了。所以test.css里的代码没有兼容

解决办法:

file-loader

把图片看成一个模块打包进来的工具。

首先图片可能通过这两个属性设置:

(1)img 的src

webpack5之前使用require的时候,会直接把require的资源返回(图片路径/名称),5之后默认返回的是个对象,里面有default属性,default属性值才是我们想要的。

(1)想使用的话就加个default

 (2)或者配置一下

(3)采用esModule的导入规范 

 (2)background 的url

 但是发现并不能正确展示,因为login.less文件会被匹配到这里

而css-loader会识别url,对于这行代码:

 css-loader看到url后会自动调换为require语法,require语法会默认导出一个esModule,解法就同上了

但是因为这里是样式文件,没法直接这样写:url(...).default

方法:不让css-loader用esModule

设置图片名称

我们期望打包后文件的名称能够按我们自己定的规则来显示:

options里面可以配置name属性,name里放的是占位符。

常见占位符:

[ext]:处理扩展名

[name]:处理文件名

[hash]:当出现文件同名的情况,hash方式组合成文件内容

[contentHash]:在file-loader里使用hash和contentHash结果不一样

[hash:<length(当前保留长度)>]:想将hash变得更短一些

规定打包路径可以用outputPath,也可以简写写到name里:

 打包后

 url-loader

把上面配置的file-loader改成url-loader:

 

url-loader和file-loader区别

file-loader会把当年图片路径返回,然后把要打包的图片资源拷贝到路径。

url-loader,默认情况下会把当前要打包的资源以base64url方式加载到代码当中。

优点:file-loader会把资源拷贝到指定的目录,访问静态资源会分开请求(比如2张图片,就要请求2次),现在只需要main.js来把所有资源都返回(请求1次),减少请求次数。

缺点:当图片很大时,相当于我们一次请求的数据量会很大,如果是首屏加载,请求时间就会更长。

url-loader内部也可以调用file-loader,通过limit属性

 如果图片大小大于1024*25,那就通过拷贝的方式,如果没有超过和这个值那就通过base64 url方式展示。

const path = require('path');
module.exports = {
    entry: './src/main.js',
    output: {
        filename: 'build.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [ //webpack默认情况下能处理js和json,其他类型都不认识,需要单独配置
            {
                test: /\.css|.less$/, //一般是一个正则表达式,用来匹配我们要处理的文件类型
                // use:[
                //     {
                //         loader:'css-loader',
                //         options:''
                //     }
                // ]
                // loader:'css-loader' // 如果只有一个loader,且这个loader没有什么配置参数,就可以这样简写
                use: ['style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            importLoaders: 1, //css-loader在工作中会往前找前1个loader处理
                            esModule: false
                        }
                    },
                    // {
                    //     loader: 'postcss-loader', // 相当于在postcss-loader里面调用postcss,postcss又提供插件autoprefixer
                    //     options: {
                    //         postcssOptions: {
                    //             plugins: ['postcss-preset-env'] // require('postcss-preset-env')
                    //         }
                    //     }
                    // }, 
                    'postcss-loader', 'less-loader']
            },
            {
                test: /\.(gif|jpe?g|png|svg)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            // esModule: false //不转为esModule
                            name: 'img/[name].[hash:6].[ext]',
                            // outputPath: 'img',
                            limit: 1024 * 25
                        }
                    }
                ]
            }
        ]
    }
}

assets

assets/resource:和file-loader功能一样:拷贝到目录

我们发现最终打包会变成两个“.”,就是配置assetModuleFilename的时候webpack会在扩展名前自动加个“.”,所以我们不需要自己加。

assets/inline:把行内资源添加到当前代码里,相当于url-loader

 assets/source:相当于raw-loader

asset模块处理图标字体

比如这样的图标样式文件

 

 

 

 webpack插件plugin

如果配置文件当中出现配置项更改,就需要重新打包,手动到dist目录下删除,然后再重新执行打包;从发布角度来说,最终会产出静态目录,比如css、img、js、index.html这种目录文件,现在我们每次打包完成都需要手动到index.html里面手动进行修改。这些操作就可以交给插件来做。

当我们有了插件之后为什么还用loader?

因为我们总觉得loader能干的事情插件也能干。

对于loader来说就是对特定的模块类型进行转换。比如webpack默认情况下可以识别js、json,但当处理图标、字体样式等时,不认识,没法当成模块对待,所以就需要webpack将这些非模块转为模块能处理的内容。工作时机:当读取文件内容就进行工作了。

插件:能做更多的事情,打包整个过程就是webpack的生命周期,它能在任意时机插进来。它也能在打包过程做优化,比如对css做压缩处理;还可以定义全局变量,让整个项目在不同文件做数据共享。

 clean-webpack-plugin

场景:配置文件当中出现配置项更改,就需要重新打包,手动到dist目录下删除,然后再重新执行打包。自动化这个删除dist目录的操作。

 html-webpack-plugin

场景:打包后产出的index.html文件,比如title、引入的src文件等都需要手动到index.html里面进行修改。

(这里为什么CleanWebpackPlugin需要解构,HtmlWebpackPlugin不需要解构是因为他们作者的导出方式不一样)

 执行npm run build

发现title是Webpack App,然后进入npm官网查看参数 

 传参:

copy-webpack-plugin

场景:把a拷贝到b位置。

但是如果拷贝的内容有重复的话会报错:

这时候就需要:(**/是格式写法,**表示当前from路径)

define-plugin

define-plugin是webpack自带的一个plugin,不用安装。

如果我们想自定义配置一套html模板。

先创建public目录,public目录里存放的一般是直接copy的不需要webpack打包的,但是后期发布时候需要的资源。

 define-plugin是用来设置这个BASE_URL的

 打包后:

babel

为什么需要babel?

比如当前项目用的react,react会去写jsx语法,或者用到ts。这些对于浏览器来说都不能直接识别,但是开发时要用。所以中间就需要有个转换的过程。

然后我们发现,默认情况下,打包之后不会对它进行任何处理 

先把babel/core安装上,(babel核心)

它也同样不能在命令行中使用。还需要安装@babel-cli才可以在命令行(npx babel这种方式)中直接使用。

输入命令行 npx babel src --out-dir build

 发现虽然有build文件夹了但是main.js并没有做转换。因为修改这个操作还需要安装对应的babel。

@babel/plugin-transform-arrow-functions:将箭头函数转换成普通函数

@babel/plugin-transform-block-scoping:处理跨作用域的,把let/const处理成var

命令行:npx babel src --out-dir build --plugins=@babel/plugin-transform-arrow-functions,@babel/plugin-transform-block-scoping

但是一个一个这样输入太麻烦了,babel也有预设。

npm i @babel/preset-env -D

npx babel src --out-dir build --presets=@babel/preset-env

babel-loader

配置方式:

(1)webpack

注意点:如果同时有browserlistrc文件和targets属性,生效的是targets属性

 

(2)单独拎出来,babel.config.js(推荐)

polyfill

webpack5基于优化打包速度的考虑,polyfill被移除掉了,用到的时候需要自己安装。(webpack4默认自动带上,webpack5可按需安装)。

使用场景:

preset-env无法把所有语法都转到浏览器平台做兼容,我们需要polyfill打补丁。

安装:npm i @babel/polyfill --save

polyfill拆分成:

core-js/stable:让babel-loader把ECMAScript核心功能填充进来。

regenerator-runtime/runtime:当需要转换generator function的时候,就可以用这个。

babel的配置:这里corejs默认用2,如果安装的是3需要写一下corejs属性。

 注意点:

在开发中用到的第三方的包中也会用到需要polyfill的东西,如果同样的地方,第三方包polyfill了,我的代码也polyfill了,在浏览器环境下就可能出现问题。所以一般需要把node_modules里的东西去除掉,不用babel。

 webpack-dev-server

方法一:watch+live server的搭配:

不足:1.编译是所有源代码都会编译。2.每次编译成功后都要进行文件读写。(性能消耗大)3.live server是vscode下的插件。4.不能实现局部刷新

方法二:webpack-dev-serve:

所有数据在内存中完成;局部更新;

方法三:webpack-dev-middleware(支持定制化操作)

webpack-dev-middleware是一个容器,它可以把webpack处理后的文件传递给服务器。

需要安装express和webpack-dev-middleware

 HMR

理解:局部动态刷新

但是加了这个还是会刷新整个页面。

可通过这里加入指定文件名,控制具体文件热更新。

React组件支持热更新

需要安装:

@babel/core

@babel/preset-react(转换jsx语法用到的插件)

@pmmmwh/react-refresh-webpack-plugin

react-refresh

Vue组件热更新

安装:

vue-template-complier

vue-loader@14:在15版本之前不需要处理plugin,之后需要手动加载插件。

publicPath

output下的publicPath默认是空字符串,告诉index.html内部的引用路径(需要加载的资源)。

规则:域名+publicPath+filename来进行访问。

devServer下的publicPath,用来指定本地服务所在的目录。(个人感觉就像是给本机该项目目录重命名。)       contentBase,场景:想访问的资源不经过webpack处理。为打包后的资源(index.html)依赖了其他资源(utils.js),告诉它去哪找其他资源。

                         watchContentBase:和contentBase配套。作用:当utils内容变化,页面会热更新。

 hot:'only':我们不希望当前页面某个组件被另外组件(某个组件依赖另一个组件)受影响。比如A组件里用到了B组件,但是B组件报错了,导致A组件无法正常显示。现在设置hot后,B报错但不影响A组件的渲染。

compress:true。开启gzip压缩。

 开启gzip压缩之后:

historyApiFallback:true。作用:将404页面自动跳转为index.html

proxy:(当index.html需要用到其他数据,然后这些数据在另外的端口上(跨域时))

例子:

resolve模块解析规则

(1)先确定路径,如果是结对路径就不用再做处理了,

如果是相对路径,基于当前文件上下文进行查找

如果是模块就直接找node_modules了。

(2)判断文件还是文件夹。如果是文件,看有没有明确后缀,没有就去找resolve下的extensions配置。如果是文件夹,进行内容补全,默认是index.js

mode模式

默认为production,production | development

production会对源码做一些丑化(比如源代码写的fn函数,webpack为了更好处理,给它变成别的字母)和优化(把多余的空格换行注释都去掉)。

development对于阅读会友好一点,会自动把webpack的devtool改成evel。

devtool

用来控制是否生成source-map,以及如何生成source-map。

当mode设置为production后,devtool就被默认添加为evel了。通过sourceURL就能定位到源代码。

source-map: 会生成.map文件。

evel-source-map: 不生成.map文件。每个模块都有对应的sourceURL保存起来,并且是以base64字符串方式塞到sourceURL。

inline-source-map:在打包后的main.js最后有sourceURL,并且是以base64字符串方式塞到sourceURL。

cheap-source-map:在报错后,只提供行信息,不提供列信息;且内容是编译后的信息。

cheap-module-source-map:源代码还原出来了;只提供行,不提供列信息。

hidden-source-map:不能直接定位源代码,定位到打包后的文件。

nosources-source-map:有.map文件;能提示出来文件的哪行报错,但是点击报错信息无法定位到具体哪行那列。

source-map比下面evel/inline-souce-map,会多发起一次请求(就是.map文件)

发布阶段不推荐用souce-map,因为会暴露源代码。

测试阶段希望很快定位到bug位置,推荐cheap-module-source-map。

source-map

为什么需要source-map?

运行在浏览器端的代码和我们编译过的代码有差异,因为经过webpack处理可能变成压缩后的一行代码。如果报错,定位不到对应哪行代码导致的错误,调错很困难,所以需要source-map。

source-map是什么?

一种映射的技术,可以把转换后的代码,给他映射成转换前的代码。这样就能定位到错误信息了。

好处:在调试时可以定位到源代码中的错误信息。

main.js.map

version:souce-map版本

file:打包后的文件

mappings:算法,映射关系。

sources:资源,告诉将来map文件通过哪些文件转换来的

sourcesContent:对源代码进行备份

names:对这里的字符进行特殊处理(比如替换操作)

sourceRoot:当前souce-map文件的根路径。

ts-loader

和less-loader有点像,依赖typescript,需要安装typescript。

只提供语法转换,不支持新的特性。

就需要用到babel-loader来兼容新特性了。

@babel/preset-typescript

如果用babel-loader来处理ts,当ts文件有语法错误时,这个错误在编译阶段没法暴露出来,只有运行代码时候才能看到错误。不影响打包操作。

而用ts-loader,在做build操作后就会暴露出来错误。

加载Vue文件

安装vue、vue-loader、vue-templete-complier

const VueLoaderPlugin=require('vue-loader/lib/plugin');
...
...
new VueLoaderPlugin()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值