webpack:基本打包方法

webpack:基本打包方法

@jarringslee

文章目录

webpack入门

webpack是一个用于现代js应用程序的 现代模块打包工具。当webpack处理应用程序时,它会在内部从一个或多个入口点构建一个依赖图(dependency graph),然后将项目中所需的每一个模块组合成一个或多个bundles,它们均为静态资源,用于展示内容。

静态模块指编写代码过程中的html css js 图片等固定内容的文件。

打包指将静态模块内容压缩、整合、转译等,即 前端工程化

  • 把 less / sass 代码转成css代码
  • 把 ES6+ 可降级成 ES5
  • 支持多种模块标准语法

使用webpack进行打包

基本打包步骤

步骤:

  1. 新建并初始化项目,编写业务源代码

  2. 下载软件包: 下载webpack webpack-cli到当前项目中,并配置局部自定义命令。一般下载全局软件包,也可以分别在各自项目文件夹中下载不同版本的软件包。

    bash 复制代码
    npm i webpack webpack-cli --save-dev

    下载后,在package.json字符串中输入以下命令:

    json 复制代码
    "scripts":{
    	"build": "webpack"
    },

    build是自定义的名字,表示在终端中输入npm run build就会执行冒号后的命令。

  3. 运行打包命令

    bash 复制代码
    npm run build

    webpack打包并输送到当前项目文件夹中的dist目录中的main.js出口文件。

需求:封装utils包,校验手机号长度和验证码长度,在src/index.js中使用并打包观察

  • 创建项目文件夹,并创建src文件夹

  • 在src文件夹中创造utils文件夹并在里面创造js文件存放工具函数

    js 复制代码
    // check.js
    // 封装两个函数:校验手机号码长度和验证码长度
    // 采用ECMAScript命名标准导出
    export const checkPhone = phone => phone.length === 11
    export const checkCode = code => code.length === 6
  • 在src文件夹中创造index.js文件把函数打包过来(如果用ECMAScript方法的话,需要在后面json文件出来后在里面添加:"type": "module"),并使用该函数(可以用console.log())

    js 复制代码
    // index.js
    // 体验webpack打包过程
    import { checkPhone, checkCode } from './utils/check.js'
    console.log(checkPhone('12312341234'))
    console.log(checkCode('12345678'))
  • 准备webpack打包环境:在项目所在终端中输入npm i webpack webpack-cli --save-dev,随后在pack.json文件中找到"scripts":{}并添加"build": "webpack"

  • 运行自定义命令并观察效果:npm run 自定义命令

命令成功后,会自动在总文件夹下创造dist文件夹并在其中创造main.js文件,在其中实现代码的压缩:

js 复制代码
(()=>{"use strict";console.log(!0),console.log(!1)})();

修改打包入口和出口

有时候打包前端代码时,文件入口有可能不是src下的index.js文件,出口也有可能不是main.js文件

步骤:

  1. 在项目根目录中设置webpack.js配置文件
  2. 导出配置对象、配置入口、出口文件的路径
  3. 重新打包观察

注意:只有和入口产生直接 / 间接的引入关系,才会被一块打包。

参考文档:概念 | webpack入口配置

入口起点设置:

入口起点(entry point) 指示 webpack 应该使用哪个模块,来作为构建其内部 依赖图(dependency graph) 的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。

默认值是 ./src/index.js,但你可以通过在 webpack configuration 中配置 entry 属性,来指定一个(或多个)不同的入口起点。例如:

创建项目配置文件webpack.config.js,放在项目的根目录下

js 复制代码
module.exports = {
entry: './path/to/my/entry/file.js',
};

出口起点设置:

output 属性告诉 webpack 在哪里输出它所创建的 bundle ,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js,其他生成文件默认放置在 ./dist 文件夹中。

你可以通过在配置中指定一个 output 字段,来配置这些处理过程:

webpack.config.js

javascript 复制代码
// commonjs 语法

const path = require('path');

module.exports = {
// 路径使用相对或者绝对都可以
entry: './path/to/my/entry/file.js',
output: {
// 只能导出一次对象
// 设置打包文件所存放的文件夹
path: path.resolve(__dirname, 'dist'),
// 设置打包文件的文件名(也可以写路径)
filename: 'my-first-webpack.bundle.js',
clean:true // 生成新的打包内容之前先清空输出目录
},
};
js 复制代码
// ECMAScript 语法(ESM)

import path from 'path';
import { fileURLToPath } from 'url';

// 在 ESM 中模拟 __dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname  = path.dirname(__filename);

export default {
// 入口路径,相对或绝对均可
entry: './path/to/my/entry/file.js',

output: {
 // 只能导出一个对象
 // 打包文件存放的目录(绝对路径)
 path: path.resolve(__dirname, 'dist'),
 // 打包出来的文件名(可含子目录)
 filename: 'my-first-webpack.bundle.js',
 clean:true // 生成新的打包内容之前先清空输出目录
},
};

在上面的示例中,我们通过 output.filenameoutput.path 属性,来告诉 webpack bundle 的名称,以及我们想要 bundle 生成(emit)到哪里。可能你想要了解在代码最上面导入的 path 模块是什么,它是一个 Node.js 核心模块,用于操作文件路径。

小案例:用户登录-长度判断

需求:点击登录按钮,判断手机号和验证码长度

步骤:

  1. 准备用户登录界面
  2. 编写核心js逻辑代码
  3. 打包并手动复制网页到dist下,引入打包后的js并运行

核心:webpack打包后的代码,作用在前端网页中使用。

设置及打包其它文件

自动生成html文件

插件:html-webpack-plugin 在webpack打包时生成html文件,帮你把打包好的js和css等模块引入好。

步骤:

  1. 在当前项目中配置好webpack环境;

  2. 下载 html-webpack-plugin 本地软件包

    bash 复制代码
    npm install --save-dev html-webpack-plugin
  3. 配置 webpack.config.js 文件,让 webpack 拥有插件功能

    ECMAScript方法:

    js 复制代码
    // webpack.config.js
    
    // 引入plugins对象
    import HtmlWebpackPlugin from 'html-webpack-plugin';
    // 在 ESM 里模拟 __dirname
    const __filename = fileURLToPath(import.meta.url);
    const __dirname = path.dirname(__filename);
    
    export default {
    	// ......设置其他内容。如更改出入口文件
        // 插件:给webpack提供更多的功能
        plugins: [
            new HtmlWebpackPlugin({
                title: 'ljl', // 可去掉
                template: path.resolve(__dirname, 'public/login.html'),  //模版文件的路径
                filename: path.resolve(__dirname, 'dist/login/index.html')  //输出文件的路径
            })
        ]
    };

    commonJS方法:

    js 复制代码
    // webpack.config.js
    
    const path = require('path');
    // 引入plugins对象
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      // ......设置其他内容。如更改出入口文件
      // 插件:给webpack提供更多的功能
      plugins: [
            new HtmlWebpackPlugin({
                title: 'ljl', // 可去掉
                template: path.resolve(__dirname, 'public/login.html'),  //模版文件的路径
                filename: path.resolve(__dirname, 'dist/login/index.html')  //输出文件的路径
            })
        ]
    };
  4. 重新打包并观察效果。

打包css代码

前情提要:webpack只识别js代码

加载器: css-loader 解析css代码

加载器:style-loader 把解析后的css代码插入到dom中

步骤:

  1. 准备css文件代码到 src/login/index.js 中(压缩转译处理等)

  2. 下载 css-loader 和 style-loader 本地软件包

    js 复制代码
    npm i --save-dev css-loader
    bash 复制代码
    npm i --save-dev style-loader
  3. 配置 webpack.config.js 文件,让webpack拥有加载器功能

    js 复制代码
    // webpack.config.js
    
    
    export default {
        // ......
        // 加载器:让webpack识别更多模块文件的内容
        module: {
            rules: [
                {
                    test: /\.css$/i,
                    use: ['style-loader', 'css-loader'],
                },
            ],
        }
    };
  4. 打包并观察效果

美化css样式

下载软件包: Bootstrap

步骤:

  1. 通过npm下载Bootstrap软件包

    bash 复制代码
    npm i bootstrap
  2. 在入口文件中引入下载好的特定的Bootstrap文件

    js 复制代码
    //index.js (入口文件)
    import 'bootstrap/dist/css/bootstrap.min.css'  // 先引入Bootstrap文件
    import './index.css'                           // 再引入css文件
  3. 打包并观察效果

提取css代码

这是一个优化的行为。将css代码单独提取成一个文件,因为css文件可以被浏览器缓存,让css文件和js文件同步下载到网页中,减少js体积

插件:mini-css-extract-plugin 提取css代码

注意 不能和style-loader一起使用

步骤:

  1. 下载 mini-css-extract-plugin 本地软件包

    bash 复制代码
    npm i --save-dev mini-css-extract-plugin
  2. 配置 webpack.config.js 让 webpack 拥有该插件功能

    引入插件

    js 复制代码
    // commonjs
    const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    js 复制代码
    // ECMAScript
    import MiniCssExtractPlugin from 'mini-css-extract-plugin'

    修改配置

    修改加载器部分:

    js 复制代码
    //把  use: ['style-loader', 'css-loader'],  改为:
    use: [MiniCssExtractPlugin.loader, 'css-loader'],
  3. 打包后观察效果

压缩css代码

在使用minicssextractplugin提取css文件时,我们编写的css部分没有被压缩,只有bootstrap部分是压缩好的。

压缩所有css代码:使用 css-minimizer-webpack-plugin 插件

步骤:

  1. 下载 css-minimizer-webpack-plugin 本地软件包

    bash 复制代码
    npm install css-minimizer-webpack-plugin --save-dev
  2. 配置webpack.config.js

    引入插件

    js 复制代码
    // commonjs
    const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
    js 复制代码
    // ECMAScript
    import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'

    修改配置

    js 复制代码
    export default {
    	// ......
        // css优化
        optimization: {
            // 最小化
            minimizer: [
                // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释,即同样压缩js代码
                `...`,
                new CssMinimizerPlugin(),
            ],
        },
    };
  3. 打包并观察效果

打包less代码

加载器: less-loader 把less代码转换为css代码

less是增强版的css语言,支持在css中添加变量、嵌套、混合编写。

less-loader需要配合less软件包一起使用

步骤:

  1. 新建 less 代码(设置背景图)并引入到 src/login/index.js 中

  2. 下载 less 和 less-loader 两个npm安装包

    js 复制代码
    npm i less less-loader --save-dev
  3. 配置webpack.config.js

    js 复制代码
    module.exports = {
      // ......
      module: 
        rules: [
            // css规则
            //......
            // less规则
            {
            	test: /\.less$/i,
            	use: [
            		// compiles Less to CSS
                        // 'style-loader',   不能和minicssextractplugin混用
                        MiniCssExtractPlugin.loader,
                        'css-loader',
                        'less-loader',
            	],
        	},
        ],
      },
    };
  4. 打包并观察效果

小问题:这里在打包之后可能会失去原有的css样式。

原因:打包之后index.less的内容覆盖了index.css的内容(即打包后,index.css文件中的内容被替换成了index.less文件的内容)

一般情况下,只需要把css文件的原内容再次填进去并重新打包即可。

其他解决方法:

方法一:调整 import 顺序

把你想优先的 CSS 放后面:

js 复制代码
import 'bootstrap/dist/css/bootstrap.min.css'
import './index.less'
import './index.css'  // 优先级最高,放最后

方法二:把 index.css 内容写进 index.less 里

避免了很多麻烦

css 复制代码
/* index.less */
@color: red;

body {
background: @color;
}

/* 把 index.css 的内容复制到这里 */
...

打包图片

资源模块:webpack5 内置资源模块(字体、图片等)打包,无需配置额外的loader

资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader:

  • asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现。
  • asset/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现。
  • asset/source 导出资源的源代码。之前通过使用 raw-loader 实现。
  • asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现。

当在 webpack 5 中使用旧的 assets loader(如 file-loader/url-loader/raw-loader 等)和 asset 模块时,你可能想停止当前 asset 模块的处理,并再次启动处理,这可能会导致 asset 重复,你可以通过将 asset 模块的类型设置为 'javascript/auto' 来解决。

步骤:

  1. 在 index.js中引入图片

    在此实例中,我们引入同目录另一文件夹下的png文件,并将其利用js拼接到html页面。

    js 复制代码
    // 本地图片利用 import 引入
    import imgObj from '../login/assets/logo.png'
    // 获取图片标签
    const theImg = document.createElement('img')
    theImg.src = imgObj
    // 插入html中
    document.querySelector('.login-wrap').appendChild(theImg)
  2. 配置webpack.config.js让webpack拥有打包图片的功能

    js 复制代码
    module.exports = {
    	// ......
    	moudle: {
    		rules: [
    		//......		
    			{
    				test:/\.(png|jpg|jpeg|gif)$/i,
    				type:'asset',
    				generator: {
    					filename:'assets/[hash][ext][query]'
    				}
    			}
    		]
    	}
    }

    注意:判断临界默认值:8KB

    • 大于8KB的文件:发送一个单独的url文件并导出url地址
    • 小于8KB的文件:导出一个data URL(base64字符串)

filename:'assets/[hash][ext][query]'中的三个占位符:

这三个占位符是 Webpack 输出文件命名时常用的模板变量 ,在 generator.filenameoutput.filename 里使用。


[hash]

  • 含义:模块内容的哈希值(hash),Webpack 根据内容生成一串十六进制字符串。
  • 作用:防止浏览器缓存旧文件。
  • 示例
js 复制代码
filename: 'assets/[hash][ext]'

如果打包一张 logo.png,生成的文件可能是:

复制代码
assets/3f5a2d1e8b.png

小技巧:可以写 [hash:8],表示只取前 8 位,更短一些:

复制代码
assets/3f5a2d1e.png

[ext]

  • 含义 :原文件的扩展名(带 .)。

  • 作用:保持文件类型一致。

  • 示例

    filename: 'assets/[hash][ext]'

原文件 logo.png → 输出 3f5a2d1e8b.png,扩展名仍然是 .png


[query]

  • 含义:文件 URL 中的查询参数(query string)。
  • 作用:如果你 import 的资源带了查询参数,会自动保留。
  • 示例
js 复制代码
import img from './logo.png?version=1'

输出文件名会是:

复制代码
assets/3f5a2d1e8b.png?version=1

在实际项目中用得比较少,主要用于带版本号或 CDN 参数的资源。

占位符 作用
[hash] 根据内容生成哈希,防缓存
[ext] 保持原文件扩展名
[query] 保留 import 时的查询参数

小案例:用户登录-完整功能

需求:完成核心的登录流程以及alert警告框的使用

步骤:

  1. 使用 npm 下载 axios

    bash 复制代码
    npm i axio
  2. 准备并修改utils工具包源代码导出实现函数

    例如:我们需要封装两个js文件:

    默认导出:

    js 复制代码
    import axios from 'axios'
    // ......
    export default axios;

    命名导出:

    js 复制代码
    export function myAlert(...){...}

    在入口函数中引入并使用:

    js 复制代码
    import myAxios from '../utils/request.js'
    import { myAlert } from '../utils/alert.js'
    
    document.querySelector('.btn').addEventListener('click', () => {
        // get phone number and id-code
        const phone = document.querySelector('.login-form [name=mobile]').value
        const code = document.querySelector('.login-form [name=code]').value
    
        if (!checkPhone(phone)) {
            myAlert(false, '手机号码输入不合法')
            console.log('手机号码输入不合法!')
            return
        }
    
        if (!checkCode(code)) {
            myAlert(false, '验证码输入不合法')
            console.log('验证码输入不合法!')
            return
        }
    
    
        myAxios({
            url: '/v1_0/authorizations',
            method: 'POST',
            data: {
                monile: phone,
                code: code
            }
        }).then(() => {
            myAlert(true, '已提交至服务器')
        }).catch(error => {
            myAlert(false, error.response.data.message)
        })
    })
  3. 导入并编写逻辑代码,打包后运行观察效果。

相关推荐
刻刻帝的海角20 分钟前
响应式数据可视化 Dashboard
开发语言·前端·javascript
小飞侠在吗21 分钟前
vue3 中的 ref 和 reactive
前端·javascript·vue.js
0思必得022 分钟前
[Web自动化] 开发者工具控制台(Console)面板
前端·javascript·python·自动化·web自动化·开发者工具
weixin_3077791324 分钟前
Jenkins Bootstrap 5 API插件:现代化Jenkins界面的开发利器
开发语言·前端·网络·bootstrap·jenkins
小毛驴85024 分钟前
快速设置 npm 源
前端·npm·node.js
花花鱼24 分钟前
nginx 解决跨域问题
前端·javascript·nginx
步步为营DotNet25 分钟前
深入解读CancellationToken:.NET异步操作的精准控制
java·前端·.net
笙年26 分钟前
Promise详解:从回调地狱到优雅异步
前端·javascript
青衫码上行27 分钟前
【JavaWeb学习 | 第17篇】JSP内置对象
java·开发语言·前端·学习·jsp