--- title: 'Webpack' date: 2020-10-10 author: 'ac' tags: - Webpack categories: - Web --- ## 1.前端工程化 实际的前端开发: - 模块化(js模块化、css模块化、资源的模块化) - 组件化(UI结构、样式、行为的复用) - 规范化(目录的结构划分、编码规范化、接口规范化) - 自动化(自动构建、部署、测试) `前端工程化`指的是:在企业级的前端项目开发中,把前端开发所需的**工具**、**技术**、**流程**、**经验**等进行规范化、 标准化。 好处:前端开发自成体系,有一套标准的开发方案和流程。 工程化解决方案: - [webpack](https://www.webpackjs.com/) - parcel ## 2. Webpack的基本使用 > webpack 是前端项目工程化的具体解决方案。 Webpack是前端资源加载/打包工具,它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。 Webpack 可以将多种静态资源 js、css、less 转换成一个静态文件,减少了页面的请求。 主要功能:它提供了友好的前端**模块化**开发支持,以及**代码压缩混淆**、处理浏览器端 JavaScript 的**兼容性**、**性能优化**等强大的功能。 **Webpack 全局安装** ```shell npm install webpack -g ``` 到了 webpack4,命令行相关的内容都移到 webpack-cli,所以还需要安装 webpack-cli ```shell npm install webpack-cli -g ``` Webpack 根据模块的依赖关系进行静态分析,这些文件(模块)会被打包到 bundle.js 文件中。 Webpack 会给每个模块分配一个唯一的 id 并通过这个 id 索引来访问模块。 --- 下面通过一个项目来手动配置`Webpack`的方式来学习: 1. 创建一个空文件夹,运行`npm init -y`,初始化一个包管理配置文件`package.json`,创建src目录并src下创建index.html和index.js image-20210907163730010 2. 安装jquery,使用jq来操作DOM,`npm i jquery -S` ```javascript import $ from "jquery" $(function(){ $("p").css("background-color","red"); }) ``` 3. 创建webpack.config.js配置文件 ```js module.exports = { mode : "development" // 选择 development 为开发模式, production 为生产模式 } ``` 4. 在`package,json`配置文件中添加脚本命令,运行`npm run dev`项目中的会从默认`src/index.js`文件作为入口,打包项目中的引用到的资源文件,并将结果输出到`dist/main.js`文件中。 ```js "scripts": { "dev": "webpack" }, ``` image-20210907171728757 5. 将`index.html`文件中对`index.js`的引用修改为引用`dist/mian.js`,在浏览器中打开就可以看到效果。 image-20210907172008755 ### 2.1 配置文件 在执行`webpack`命令时,webpack会去寻找项目中的webpack.config.js配置文件,根据配置项对项目进行打包。 - 入口(entry):入口会指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。 - loader:让 webpack 可以去处理那些非 JavaScript 文件。 - output:属性告诉webpack在哪里输出(path)它创建的bundles,以及如何命名这些文件(filename) - 插件(plugins): > 在`webpack4.x`和`webpack5.x`的版本中有默认的打包入口文件(`src/index.js`)和默认的输出文件路径(`dist/main.js`) ```javascript const path = require('path'); // 使用 Node.js 中的导出语法,向外导出一个 webpack 的配置对象 module.exports = { //SourceMap 源码与压缩文件的映射文件,生成阶段建议关闭 devtool: "eval-source-map", // development 为开发模式, production 生产模式(会压缩混淆代码) mode: "development", //指定要处理入口文件 entry: path.join(__dirname,"./src/index.js"), // 指定生成的文件要存放到哪里 output: { // 存放的目录 path:path.resolve(__dirname, 'dist/js/'), //表示当前执行脚本所在的目录。(路径) // 生成的文件名 filename: "bundle.js" } }; ``` ### 2.2插件 插件在 webpack 的配置信息 plugins 选项中指定,用于完成一些 loader 不能完成的工作。常用插件: 1. `webpack-dev-server`:当修改源码时,项目自动打包和构建 ```shell npm install webpack-dev-server --save-dev ``` 2. `html-webpack-plugin`:项目首次构建完成后自动打开项目文件 ```shell npm i --save-dev html-webpack-plugin ``` 3. `clean-webpack-plugin`:清除每次打包的输出目录(`dist`)中原有的文件 ```shell npm install --save-dev clean-webpack-plugin ``` 插件`dev-server`的使用: 需要在package.json文件中的脚本命令中添加serve参数: ```javascript "scripts": { "dev": "webpack serve", }, ``` > dev-server插件会启动一个实时打包的http服务,所以打开项目的时候是http协议开头 在`webpack.config.js`文件中`dev-server`插件可以通过`devserver`节点配置地址和端口: ```javascript "devserver":{ open: true, host: '127.0.0.1', port: 9527 } ``` ![image-20220218111225479](./images/image-20220218111225479.png) ![image-20220218111548844](./images/image-20220218111548844.png) > `dev-server`插件会在内存中创建打包好的`bundle.js`文件,没有存储在物理磁盘中。首页中也会引入内存中的`bundle.js`文件 插件`html-webpack-plugin`的使用: 需要在`webpack.config.js`文件中进行配置 ```javascript // 1. 导入 html-webpack-plugin 这个插件,得到插件的构造函数 const HtmlPlugin = require('html-webpack-plugin') // 2. new 构造函数,创建插件的实例对象 const htmlPlugin = new HtmlPlugin({ // 指定要复制哪个页面 template: './src/index.html', // 指定复制出来的文件名和存放路径 filename: './index.html' }) module.exports = { ... //3. 将插件实例对象配置到webpack中 plugins:[htmlPlugin] ... } ``` 插件`clean-webpack-plugin`的使用: 跟上一个插件方法一样,也是创建插件实例,配置`plugins`配置项. ```javascript const { CleanWebpackPlugin } = require('clean-webpack-plugin') module.exports = { ... //3. 将插件实例对象配置到webpack中 plugins:[htmlPlugin,new CleanWebpackPlugin()] ... } ``` 完成的配置文件如下: ```javascript const path = require('path'); // 1. 导入 html-webpack-plugin 这个插件,得到插件的构造函数 const HtmlPlugin = require('html-webpack-plugin') // 2. new 构造函数,创建插件的实例对象 const htmlPlugin = new HtmlPlugin({ // 指定要复制哪个页面 template: './src/index.html', // 指定复制出来的文件名和存放路径 filename: './index.html' }) const { CleanWebpackPlugin } = require('clean-webpack-plugin') // 向外导出一个 webpack 的配置对象 module.exports = { //SourceMap 源码与压缩文件的映射文件,生成阶段建议关闭,可选值:source-map、eval-source-map、nosources-source-map。若配置了该项,则打包会生成一个记录映射关系的*.map文件 devtool: "nosources-source-map", // development 为开发模式, production 生产模式(会压缩混淆代码) mode: "development", //指定要处理入口文件 entry: "./src/index.js", // 指定生成的文件要存放到哪里 output: { // 存放的目录 path:path.resolve(__dirname, 'dist'), //表示当前执行脚本所在的目录。(路径) // 生成的文件名 filename: "js/bundle.js" }, devServer: { open: true, host: '127.0.0.1', port: 9527 }, // 插件的数组,将来 webpack 在运行时,会加载并调用这些插件 plugins: [htmlPlugin, new CleanWebpackPlugin()], }; ``` ### 2.3 loader Webpack 本身只能处理 JS文件,如果要处理其他类型的文件,**就需要使用 loader 进行转换**。 比如加载CSS文件,需要使用css-loader和style-loader - css-loader:遍历css文件,找到url()表达式; - style-loader:将css代码嵌入页面中的一个style标签中; ![image-20220218112340763](./images/image-20220218112340763.png) 常用的`loader`: 1. 样式相关的`css-loader`、`style-loader`、`less-loader` 2. 路径相关的`url-loader`、`file-loader` 3. `ES6`相关的`babel-loader`,使用`bable`需要创建一个`babel.config.js`配置文件(设置转码规则) ```javascript //css相关的包 npm install --save-dev css-loader npm install --save-dev style-loader //less相关的包 npm install less less-loader --save-dev //图片相关的包 npm install url-loader --save-dev npm install file-loader --save-dev //Babel相关的包 npm install -D babel-loader @babel/core @babel/plugin-proposal-decorators ``` 在`webpack.config.js`文件中的`module`节点添加一个`rules`数组,用于添加loader规则: ```javascript module: {//所有第三方文件模块的匹配规则 rules: [// 定义了不同模块对应的 loader //处理css文件的loader,注意loader的顺序(执行顺序是从后往前的,先css-loader处理,将结果交给style-loader,最后再交给webpack打包到bundle.js文件中) { test: /\.css$/, use: ['style-loader', 'css-loader'] }, // 处理 .less 文件的 loader { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }, // 处理图片文件的 loader // 如果需要调用的 loader 只有一个,则只传递一个字符串也行,如果有多个loader,则必须指定数组 // 在配置 url-loader 的时候,多个参数之间,使用 & 符号进行分隔 { test: /\.jpg|png|gif$/, use: 'url-loader?limit=880&outputPath=images' }, // 使用 babel-loader 处理高级的 JS 语法 // 在配置 babel-loader 的时候,程序员只需要把自己的代码进行转换即可;一定要排除 node_modules 目录中的 JS 文件 // 因为第三方包中的 JS 兼容性,不需要程序员关心 { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ } ] }, resolve: { alias: { // 告诉 webpack,程序员写的代码中,@ 符号表示 src 这一层目录,这样查找资源可以从外往里找 '@': path.join(__dirname, './src/') } } ``` `outputPath`参数可以设置编译打包后图片的生成位置; `limit`参数用于设置多大的图片需要转码为base64格式; `exclude`参数排除不需要转码的文件。 使用`babel`需要在项目根目录中添加一个`babel.config.js`配置文件,用于指定转换规则: ```javascript // 向外导出一个 babel 的配置对象 module.exports = { plugins:[ //以插件的形式,添加支持的转码规则,如下面的修饰器语法,class类语法 "@babel/plugin-proposal-decorators", "@babel/plugin-proposal-class-properties" ] } ```