Webpack使用入门

这里介绍webpack的基本使用。

1、打包js后引用

1.1 文件准备

在一个单独的目录中新建配置文件00_webpackhello/package.json

{  
  "name": "00_webpackhello",  
  "version": "1.0.0",  
  "description": "",  
  "main": "index.js",  
  "scripts": {  
    "test": "echo \"Error: no test specified\" && exit 1",  
    "build": "webpack --mode development"  
  },  
  "keywords": [],  
  "author": "",  
  "license": "ISC",  
  "devDependencies":{  
    "webpack": "^5.74.0",  
    "webpack-cli": "^4.10.0"  
  }  
}

在同目录下新建配置文件00_webpackhello/webpack.config.js

const path = require('path');  
  
module.exports = {  
    entry: './src/main.js',  
    output: {  
        path: path.resolve(__dirname, 'dist'),  
        filename: 'bundle.js',  
    },  
};

在相同目录下新建src目录,并创建待打包的js文件。
00_webpackhello/src/compute.js

var testNum1 = 6, testNum2 = 3;  
function add(a, b) {  
    return a + b;  
}  
function minus(a, b) {  
    return a - b;  
}  
function multiply(a, b) {  
    return a * b;  
}  
function divide(a, b) {  
    return a / b;  
}  
//这里导出一个默认变量  
export {  
    add,  
    minus,  
    multiply,  
    divide  
}

00_webpackhello/src/main.js

import * as tmp from './compute.js'  
var num1 = 10, num2 = 2;  
alert("testNum1: " + ", testNum2: " +  " " + tmp.add(num1, num2) + " " + tmp.minus(num1, num2)+ " " + tmp.multiply(num1, num2)+ " " + tmp.divide(num1, num2));

添加gitignore配置文件00_webpackhello/.gitignore

dist/  
node_modules/

新建一个测试html文件,用于引用打包后的js文件,看是否有效。
00_webpackhello/index.html

<!-- 其他省略 -->  
<body>  
<script src="dist/bundle.js"></script>  
</body>

1.2 环境安装

在当前目录下执行如下npm install命令,npm会自动根据package.json配置文件中的依赖进行安装。

$ npm install

up to date in 692ms
$ 

执行完成后,这个目录下会生成一个package-lock.json配置文件,我们一般不用管它。同时,前面在package.json中配置的依赖,应该会自动安装到00_webpackhello/node_modules目录下。

1.3 打包

在当前目录下执行打包命令:

$ npm run build

> 00_webpackhello@1.0.0 build
> webpack --mode development

asset bundle.js 4.79 KiB [emitted] (name: main)
runtime modules 670 bytes 3 modules
cacheable modules 513 bytes
  ./src/main.js 219 bytes [built] [code generated]
  ./src/compute.js 294 bytes [built] [code generated]
webpack 5.75.0 compiled successfully in 132 ms
$ 

在当前目录会新生成一个dist目录,其中包含打包生成的文件00_webpackhello/dist/bundle.js。打包之后的完整目录结构如下图。

image.png

1.4 测试

这时候,如果在浏览器中打开前面创建的index.html,可以看到js已经生效。如下图。


image.png

2、打包为js依赖库

2.1 直接作为依赖库引用报错

前面的例子中,如果在index.html中直接写一个script标签,调用add函数,如下:

<!-- 其他省略 -->  
<body>  
<script src="dist/bundle.js"></script>  
<script>  
    alert(add(1,2));  
</script>  
</body>

会报错add没有定义。这是因为在javascript的模块化语法里面,在每一个模块文件中定义的函数和变量都是局部变量,所以,在模块范围之外没法引用。

2.2 依赖库打包配置说明

webpack支持将js文件打包为依赖库,供其他人调用。通过library的配置可以支持指定库的名称, libraryTarget指定库打包出来的规范。
其中,可选的值有“var、assign、this、window、global、commonjs、commonjs2、commonjs”。
不同取值的打包行为说明如下:

// var config  
{  
    output: {  
        library: 'myLib',  
            filename: 'var.js',  
            libraryTarget: 'var'  
    }  
}  
// output  
var myLib = (function (modules) { })({  
    './src/index.js': function (module, exports) { }  
});  
// ===============================================  
  
// assign config  
{  
    output: {  
        library: 'myLib',  
            filename: 'assign.js',  
            libraryTarget: 'assign'  
    }  
}  
// output: 少了个 var  
myLib = (function (modules) { })({  
    './src/index.js': function (module, exports) { }  
});  
// ===============================================  
  
// this config{  
{  
    output: {  
        library: 'myLib',  
            filename: 'this.js',  
            libraryTarget: 'this'  
    }  
}  
// output  
this["myLib"] = (function (modules) { })({  
    './src/index.js': function (module, exports) { }  
});  
// ===============================================  
  
// window config  
{  
    output: {  
        library: 'myLib',  
            filename: 'window.js',  
            libraryTarget: 'window'  
    }  
}  
// output  
window["myLib"] = (function (modules) { })({  
    './src/index.js': function (module, exports) { }  
});  
// ===============================================  
  
// global config  
{  
    output: {  
        library: 'myLib',  
            filename: 'global.js',  
            libraryTarget: 'global'  
    }  
}  
  
// output:注意 target=node 的时候才是 global,默认 target=web下global 为 window  
window["myLib"] = (function (modules) { })({  
    './src/index.js': function (module, exports) { }  
});  
// ===============================================  
  
// commonjs config  
{  
    output: {  
        library: 'myLib',  
            filename: 'commonjs.js',  
            libraryTarget: 'commonjs'  
    }  
}  
// output  
exports["myLib"] = (function (modules) { })({  
    './src/index.js': function (module, exports) { }  
});  
// ===============================================  
  
// amd config  
{  
    output: {  
        library: 'myLib',  
            filename: 'amd.js',  
            libraryTarget: 'amd'  
    }  
}  
// output  
define('myLib', [], function () {  
    return (function (modules) { })({  
        './src/index.js': function (module, exports) { }  
    });  
});  
// ===============================================  
  
// umd config  
{  
    output: {  
        library: 'myLib',  
            filename: 'umd.js',  
            libraryTarget: 'umd'  
    }  
}  
// output  
(function webpackUniversalModuleDefinition(root, factory) {  
    if (typeof exports === 'object' && typeof module === 'object')  
        module.exports = factory();  
    else if (typeof define === 'function' && define.amd) define([], factory);  
    else if (typeof exports === 'object') exports['myLib'] = factory();  
    else root['myLib'] = factory();  
})(window, function () {  
    return (function (modules) { })({  
        './src/index.js': function (module, exports) { }  
    });  
});  
// ===============================================  
  
// commonjs2 config  
{  
    output: {  
        library: 'myLib',  
            filename: 'commonjs2.js',  
            libraryTarget: 'commonjs2'  
    }  
}  
//output  
module.exports = (function(modules) {})({  
    './src/index.js': function(module, exports) { }  
});  
// ===============================================  
  
// umd2 config  
{  
    output: {  
        library: 'myLib',  
            filename: 'umd2.js',  
            libraryTarget: 'umd2'  
    }  
}  
// output  
(function webpackUniversalModuleDefinition(root, factory) {  
    if (typeof exports === 'object' && typeof module === 'object')  
        module.exports = factory();  
    else if (typeof define === 'function' && define.amd) define([], factory);  
    else if (typeof exports === 'object') exports['myLib'] = factory();  
    else root['myLib'] = factory();  
})(window, function () {  
    return (function (modules) { })({  
        './src/index.js': function (module, exports) {  
        }  
    });  
});  
// ===============================================  
  
// commonjs-module config  
{  
    output: {  
        library: 'myLib',  
            filename: 'commonjs-module.js',  
            libraryTarget: 'commonjs-module'  
    }  
}  
// output  
module.exports = (function (modules) { })({  
    './src/index.js': function (module, exports) { }  
});  
// ===============================================  
  
// jsonp config  
{  
    output: {  
        library: 'myLib',  
            filename: 'jsonp.js',  
            libraryTarget: 'jsonp'  
    }  
}  
// output  
myLib((function (modules) { })({  
    './src/index.js': function (module, exports) { }  
}));  
// ===============================================

简单说明见下图:


image.png

2.3 依赖库打包示例

这里将前面的例子中的代码,打包为可以在script标签中引用的依赖库。
首先,修改打包的配置文件00_webpackhello/webpack.config.js

const path = require('path');

module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
        //指定打包后的库通过全局变量的方式暴露
        libraryTarget: "var",
        //指定打包后的库名
        library: "MATH"
    },
};

然后,修改测试文件00_webpackhello/index.html,在script标签中调用前面的依赖函数,如下。

<!-- 其他省略 -->  
<body>  
<script src="dist/bundle.js"></script>  
<script>  
    alert(MATH.add(1,2));  
</script>  
</body>

这样,在00_webpackhello目录下执行npm run build打包命令之后,在浏览器中打开测试文件00_webpackhello/index.html,可以看到能够正常被调用。第一个alert弹出之后,第二个alert,也可以正常弹出,如下图:

image.png

实际上,这样打包之后,也可以在单独的js文件中引用。这里新建一个00_webpackhello/callTest.js文件:

alert(MATH.multiply(22,2));

在测试文件00_webpackhello/index.html中,引用这个文件,如下:

<!-- 其他省略 -->  
<body>  
<script src="dist/bundle.js"></script>  
<script src="callTest.js"></script>  
<script>  
    alert(MATH.add(1,2));  
</script>  
</body>

在浏览器中打开上述测试文件之后,可以看到三个alert框,说明在单独的js文件中,也可以被调用到。

3、打包css

3.1 将css打包到js中

3.1.1 预处理器css-loader和style-loader简介

这里需要用到两个预处理器css-loader和style-loader。css-loader的作用是解析css文件,包括解析@import等css自身语法,它会将解析后的css文件以字符串的形式打包到js文件中(但此时,css样式并不会生效,因为需要把css文件插入到html中才会生效)。style-loader的作用就是把js中的样式代码插入到html中。它的原理很简单,就是通过动态生成style标签并将其插入到html文件的head标签中。

3.1.2 打包css到js示例

在一个新的目录01_webpackhello中新建如下文件。
npm配置文件,01_webpackhello/package.json

{  
  "name": "00_webpackhello",  
  "version": "1.0.0",  
  "description": "",  
  "main": "index.js",  
  "scripts": {  
    "test": "echo \"Error: no test specified\" && exit 1",  
    "build": "webpack --mode development"  
  },  
  "keywords": [],  
  "author": "",  
  "license": "ISC",  
  "devDependencies": {  
    "css-loader": "^6.7.2",  
    "style-loader": "^3.3.1"  
  }  
}

webpack配置文件,01_webpackhello/webpack.config.js

const path = require('path');  
  
module.exports = {  
    entry: './src/main.js',  
    output: {  
        path: path.resolve(__dirname, 'dist'),  
        filename: 'bundle.js'  
    },  
    module: {  
        rules: [  
            {  
                test: /\.css$/i,  
                //执行顺序从右向左,将css-loader处理后的结果传给style-loader  
                use: ['style-loader', 'css-loader'],  
            },  
        ],  
    },  
};

添加gitignore配置文件01_webpackhello/.gitignore

dist/  
node_modules/

新建javascript代码,01_webpackhello/src/main.js

import './css/all.css'; // 使用 ESM 方式引入  
const name = 'Paopao';  
alert('Hello ' + name);  
console.log('Hello ' + name);

新建css代码,01_webpackhello/src/css/all.css

.text-primary {
    color: rgb(37, 37, 177);
}

新建一个测试打包效果的html文件,01_webpackhello/index.html

<html>
<head>
    <!-- 引入打包生成的 JavaScript -->
    <script src="dist/bundle.js"></script>
</head>
<body>
<h1 class="text-primary" id="hello_h1">Hello World</h1>
</body>
</html>

在该目录下执行npm install命令,npm会自动根据package.json配置文件中的依赖进行安装。
然后,执行npm run build命令,就可以执行打包操作。打包后的目录结构如下。

image.png

这时候,在浏览器中打开前面新建的01_webpackhello/index.html,可以看到css已经生效,弹出alert框之后,字体显示为蓝色,如下。

image.png

3.2 处理css引入的图片

3.2.1 file-loader简介

file-loader是一个文件资源预处理器,作用是:处理文件导入语句(比如js的import ... from ...和css中的url())并替换成它的访问地址,同时把文件输出到相应的位置。

3.2.2 处理css引入图片的打包示例

首先,修改npm配置文件01_webpackhello/package.json

{
  "name": "00_webpackhello",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --mode development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "css-loader": "^5.0.2",
    "style-loader": "^2.0.0",
    "file-loader": "^5.1.0"
  }
}

注意:如果style-loader、css-loader、file-loader这几个的版本号不配套,会导致一个图片打包后生成两个,其中一个还不能用的情况。
修改webpack配置文件,增加file-loader的处理,01_webpackhello/webpack.config.js

const path = require('path');

module.exports = {
   entry: './src/main.js',
   output: {
       path: path.resolve(__dirname, 'dist'),
       filename: 'bundle.js'
   },
   module: {
       rules: [
           {
               test: /\.css$/I,
               //执行顺序从右向左,将css-loader处理后的结果传给style-loader
               use: ['style-loader', 'css-loader'],
           },
           {
               test: /\.png$/,
               use: "file-loader"
           }
       ],
   },
};

修改样式表文件,01_webpackhello/src/css/all.css

.text-primary {  
    color: rgb(37, 37, 177);  
}  
body{  
    background: url("img/cat.png") no-repeat;  
}

同时,新增一个图片文件img/cat.png
在该目录下执行npm install命令,npm会自动根据package.json配置文件中的依赖进行安装。
然后,执行npm run build命令,就可以执行打包操作。打包后的目录结构如下。

image.png

这时,在浏览器中打开前面新建的01_webpackhello/index.html,可以看到css已经生效,弹出alert框之后,字体显示为蓝色,并且有背景图片,如下。

image.png

3.2.3 指定css引入图片打包后的文件名和存放路径

前面的例子中,可以看出,css引用的图片在打包之后,文件名成了一个hash串。如果我们想要指定图片文件名和存放位置,只需要修改webpack配置文件,给file-loader传入options。如下。
01_webpackhello/webpack.config.js

const path = require('path');

module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.css$/I,
                //执行顺序从右向左,将css-loader处理后的结果传给style-loader
                use: ['style-loader', 'css-loader'],
            },
            {
                test: /\.png$/,
                use: {
                    loader: "file-loader",
                    options: {
                        name: 'img/[name].[ext]'
                    }
                }
            }
        ],
    },
};

执行npm run build命令,就可以执行打包操作。打包后的目录结构如下。

image.png

,在浏览器中打开前面新建的01_webpackhello/index.html,可以看到css已经生效,弹出alert框之后,字体显示为蓝色,并且有背景图片,如下。

image.png

3.3 将css打包成到单独的文件

还是前面的例子,代码不变,修改打包的相关配置。
首先,修改npm配置文件01_webpackhello/package.json,增加mini-css-extract-plugin依赖:

{  
  "name": "00_webpackhello",  
  "version": "1.0.0",  
  "description": "",  
  "main": "index.js",  
  "scripts": {  
    "test": "echo \"Error: no test specified\" && exit 1",  
    "build": "webpack --mode development"  
  },  
  "keywords": [],  
  "author": "",  
  "license": "ISC",  
  "devDependencies": {  
    "css-loader": "^5.0.2",  
    "style-loader": "^2.0.0",  
    "file-loader": "^5.1.0",  
    "mini-css-extract-plugin": "^2.6.1"  
  }  
}

修改打包的配置文件01_webpackhello/webpack.config.js,这里将css打包到dist/css/img/main.css

const path = require('path');  
//step 1: 加载mini-css-extract-plugin  
const MiniCssExtractPlugin = require('mini-css-extract-plugin');  
  
module.exports = {  
    //这样,可以配置多个entry,同时打包多个文件  
    entry: {  
      main: './src/main.js',  
    },  
    output: {  
        path: path.resolve(__dirname, 'dist'),  
        filename: 'bundle.js'  
    },  
    module: {  
        rules: [  
            {  
                test: /\.css$/i,  
                //执行顺序从右向左,将css-loader处理后的结果传给MiniCssExtractPlugin.loader  
                use: [MiniCssExtractPlugin.loader, 'css-loader'],  
            },  
            {  
                test: /\.png$/,  
                use: {  
                    loader: "file-loader",  
                    options: {  
                        name: 'css/img/[name].[ext]'  
                    }  
                }  
            }  
        ],  
    },  
  
    //step 2: 创建mini-css-extract-plugin实例  
    plugins: [  
        new MiniCssExtractPlugin({  
            //指定css输出的文件  
            filename: 'css/[name].css'  
        })  
    ]  
};

修改测试的html文件01_webpackhello/index.html,引用前面打包的css:

<html>  
<head>  
    <!-- 引入打包生成的 JavaScript -->  
    <!--<script src="dist/bundle.js"></script>-->    <link rel="stylesheet" href="dist/css/main.css"/>  
</head>  
<body>  
<h1 class="text-primary" id="hello_h1">Hello World</h1>  
</body>  
</html>

在该目录下执行npm install命令,npm会自动根据package.json配置文件中的依赖进行新增安装mini-css-extract-plugin
然后,执行npm run build命令,就可以执行打包操作。

image.png

,在浏览器中打开前面新建的01_webpackhello/index.html,可以看到css已经生效,弹出alert框之后,字体显示为蓝色,并且有背景图片,如下。

image.png

3.4 使用asset modules处理图片文件

asset modules是webpack5新加入的功能,称为资源模块,通过它,无需使用额外的预处理器,就可以将图片和字体等文件进行解析和处理。
在上面例子的基础上,修改webpack打包的配置文件01_webpackhello/webpack.config.js,通过asset modules处理图片资源:

const path = require('path');  
//step 1: 加载mini-css-extract-plugin  
const MiniCssExtractPlugin = require('mini-css-extract-plugin');  
  
module.exports = {  
    //这样,可以配置多个entry,同时打包多个文件  
    entry: {  
      main: './src/main.js',  
    },  
    output: {  
        path: path.resolve(__dirname, 'dist'),  
        filename: 'bundle.js'  
    },  
    module: {  
        rules: [  
            {  
                test: /\.css$/i,  
                //执行顺序从右向左,将css-loader处理后的结果传给MiniCssExtractPlugin.loader  
                use: [MiniCssExtractPlugin.loader, 'css-loader'],  
            },  
            {  
                test: /\.png$/,  
                type: 'asset/resource',  
                generator: {  
                    filename: 'css/img/[name].[ext]'  
                }  
            }  
        ],  
    },  
  
    //step 2: 创建mini-css-extract-plugin实例  
    plugins: [  
        new MiniCssExtractPlugin({  
            //指定css输出的文件  
            filename: 'css/[name].css'  
        })  
    ]  
};

执行npm run build命令,就可以执行打包操作。

image.png

,在浏览器中打开前面新建的01_webpackhello/index.html,可以看到css已经生效,弹出alert框之后,字体显示为蓝色,并且有背景图片,如下。

image.png

参考资料

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • webpack有什么作用? Webpack 是一个前端资源加载/打包工具,只需要相对简单的配置就可以提供前端工程化...
    宁静的夜阅读 2,704评论 0 4
  • node安装就自行百度吧! 确保你已经进入项目根目录,npm init 创建 package.json 文件 we...
    ysp123阅读 422评论 0 0
  • 前提:先安装好nodejs,并配置好环境变量。可以全局使用node npm 命令 1. 初始化项目 新建一个目录,...
    Kagari阅读 798评论 0 0
  • 什么是webpack?我的理解是文件打包及资源处理,当然功能肯定不局限于此。学习前提:了解npm,了解node.j...
    yozosann阅读 1,725评论 2 15
  • webpack的主要功能 它提供了友好的前端模块化开发的支持,以及代码压缩混淆、处理浏览器端javascript ...
    stamSuper阅读 2,813评论 0 1