手把手教你使用webpack打包前端组件(三)
这是我参与更文挑战的第9天,活动详情查看: 更文挑战
回顾前面
回顾前两篇文章中,我们从一个现成的webpack-template
中,逐步逐步地修改构建出了一个组件调试的页面,当组件调试没问题之后,我们就要对组件进行一个打包操作让其他用户可以使用。
如果还没有阅读第一,二篇的小伙伴们, 请点击阅读: 手把手教你使用webpack打包前端组件(一)
手把手教你使用webpack打包前端组件(二)
打包组件
执行npm run build
命令进行项目打包 ~ ~
打包后分别有html
和js
文件,我们使用编辑器打开Drag.html
,发现html中已经帮我们引入了Drag.js
了,其实在这里边它已经引入better-draggable-ball
了,再使用浏览器打开后发现拖拽球是可以被正常显示出来的。
当我们重新创建一个HTML
文件,引入better-draggable-ball
时,再按原来ts
中的写法会发现:
难道我们只能引入已经配置好配置项的Drag么???
强大的webpack
也给我们提供了output.library
选项,webpack
打包时可以将你的项目作为一个库来导出
我们修改webpack.config.ts
配置文件,将我们的项目中的better-draggable-ball
作为一个库来导出
在web
entry: {
'better-draggable-ball': './src/components/better-draggable-ball/index.ts'
},
在output
属性中添加library
属性。
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
clean: true,
library:'betterDraggableBall',
},
将plugins
属性中的HtmlWebpackPlugin
进行删除,因为我们已经不需要导出HTML
文件了,只需要导出js
文件让其用户去引用就可以了。
plugins: [
new ESLintPlugin({
extensions: ['js', 'ts'],
exclude: '/node_modules/',
}),
],
附上完整的webpack.config.ts
配置文件代码:
import * as path from 'path';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import ESLintPlugin from 'eslint-webpack-plugin';
import * as webpack from 'webpack';
const config: webpack.Configuration = {
mode: 'production',
entry: {
'better-draggable-ball': './src/components/better-draggable-ball/index.ts', // better-draggable-ball 插件
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
clean: true,
library: 'betterDraggableBall'
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
// 将 JS 字符串生成为 style 节点
'style-loader',
// 将 CSS 转化成 CommonJS 模块
'css-loader',
// 将 Sass 编译成 CSS
'sass-loader',
],
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new ESLintPlugin({
extensions: ['js', 'ts'],
exclude: '/node_modules/',
}),
],
};
export default config;
接下来我们再打包一下,可以看到这次dist
文件夹中只输出了better-draggable-ball
文件。
接下来,我们在dist
文件夹中创建一个test.html
文件,利用script
标签引入一下,然后使用console.log
来打印下betterDraggableBall
看看里边是什么?
很明显,打印出来的是个Object,里边只有一个default
的函数,我们打印下试试。
是一个函数,我们仔细一看,诶?这不是我们的Drag
么?
我们试试看能不能new一下试试 。
<script src="../dist/better-draggable-ball.js"></script>
<script>
window.onload = () => {
let DragDom = document.getElementById('drag')
Drag = new betterDraggableBall.default(DragDom)
console.log(Drag);
}
</script>
在webpack.config.ts
中配置下library
,让default
中的数据作为默认导出对象,type属性是配置库的暴露方式,之后再打包一下
library: {
name: 'betterDraggableBall',
type: 'umd',
export: 'default',
},
打印下betterDraggableBall
对象,这次我们可以看到没有default
这个属性了,而是将default
里的内容放到了betterDraggableBall
对象根部了,也就是说现在可以直接直接new
一个betterDraggableBall
类了
我们现在只达到了可以通过script
标签来引入组件了
支持更多的引入方式
- 定个小目标
- 我们需要输出的文件是(分别为压缩和未压缩版本):
- 一个
CommonJS
格式的js
文件 - 一个
UMD
格式的js
文件 ESM
格式的js
文件
- 一个
- 我们需要输出的文件是(分别为压缩和未压缩版本):
这里给大家简单的讲下这些格式
CommonJS
CommonJS
是服务器端模块的规范,Node.js采用了这个规范。,主要语法:比如加载模块使用的是require
方法,导出模块使用的是export
,CommonJS
加载模块是同步的,所以只有加载完成才能执行后面的操作。
AMD
AMD
全称 Asyncchronous Module Definition
,一般应用在浏览器端(这是与 CommonJS
规范最大的不同点),最著名的 AMD 加载器是 RequireJS
。目前由于 webpack
的流行, AMD
这一模块化方案已逐渐退出市场。
UMD
UMD
是AMD
和CommonJS
的糅合,以及最传统的全局变量模式。全局变量模式即是把库的入口挂载在一个全局变量(window.xxx
)上,页面上的任何位置都能随时取用,属于最传统的 js
插件加载方案,它的出现也是解决跨平台的问题。UMD先判断是否支持Node.js的模块(exports)是否存在,存在则使用Node.js模块模式。在判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块。
ESM
esm
即 es6 模块,在之前常用的是 CommonJS
和基于 AMD
的其他模块系统,ES Modules 的关键字是 import
和 export
,也是目前最流行的一种导入方式。
我们需要修改webpack
的配置文件,之前我们打包项目都是使用单独的一种配置方式,但是我们现在需要导出多种类型文件,这时webpack
给我们提供了导出多种配置方式的写法(webpack
3.1.0 起支持),把webpack.config.ts
修改如下:
import * as path from 'path';
import { Configuration as webpackConfiguration } from 'webpack';
import ESLintPlugin from 'eslint-webpack-plugin';
const outputConfig: webpackConfiguration[] = [
{
output: {
path: path.resolve(__dirname, 'dist/commonjs'),
filename: '[name].js',
clean: true,
library: {
name: 'betterDraggableBall',
type: 'commonjs',
export: 'default',
},
},
},
{
output: {
path: path.resolve(__dirname, 'dist/umd'),
filename: '[name].js',
clean: true,
library: {
name: 'betterDraggableBall',
type: 'umd',
export: 'default',
},
},
},
{
output: {
path: path.resolve(__dirname, 'dist/module'),
filename: '[name].js',
clean: true,
module: true,
library: {
type: 'module',
},
},
experiments: {
outputModule: true,
},
},
];
const baseConfig: webpackConfiguration = {
mode: 'development',
entry: {
'better-draggable-ball': './src/components/better-draggable-ball/index.ts', // better-draggable-ball 插件
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.s[ac]ss$/i,
use: [
// 将 JS 字符串生成为 style 节点
'style-loader',
// 将 CSS 转化成 CommonJS 模块
'css-loader',
// 将 Sass 编译成 CSS
'sass-loader',
],
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
plugins: [
new ESLintPlugin({
extensions: ['js', 'ts'],
exclude: '/node_modules/',
}),
],
};
const config:webpackConfiguration[]|[] = [];
for (let i: number = 0; i < outputConfig.length; i += 1) {
config[i] = Object.assign(outputConfig[i], baseConfig);
}
export default config;
这里边,我定义了2个数组,一个是baseConfig
,它用来存放webpackConfig
的基本配置,另外一个是outputConfig
,它存放了三种导出方式,分别为commonjs
,umd
,module
,最后我使用了循环和对象合并方法把基本配置对象和不同的output
属性进行一个合并生成导出一个新的webpackConfig
模块。
// 合并的语句
const config:webpackConfiguration[]|[] = [];
for (let i: number = 0; i < outputConfig.length; i += 1) {
config[i] = Object.assign(outputConfig[i], baseConfig);
}
我们打包试一下,看看是不是生成了多种导入方式的文件:
nice!接下来我们创建一个普通的HTML
文件使用script
标签引用试一下(umd
)。
<script src="./dist/umd/better-draggable-ball.js"></script>
<script>
console.log(betterDraggableBall);
</script>
接下来,再试试ESM版本的,这里我新建了一个vue vite
项目,在项目中的组件中引入它。
// 忽略一些代码 只列出主要代码
import Drag from './better-draggable-ball'
setup: () => {
const DragDom=ref<HTMLElement|null>(null)
// 拖拽组件 初始化
onMounted(()=>{
new Drag(DragDom.value, {
defaultPosition: { x: 10, y: 10 },
autoAdsorbent: true,
});
})
return{
DragDom
}
}
压缩环节
为什么要进行压缩处理
通常,开源的插件、库代码都会提供两种版本:
- 可读版,一般为开发人员准备的
- 压缩版,一般为生产环境中提供使用的
压缩版的好处:
- 减少了文件的体积
- 减少了网络传输时使用的带宽占用
- 减少了服务器的压力
我们使用的是webpack5版本以上的,无需terser-webpack-plugin
插件,直接使用就可以了。
但我们还需要执行下以下命令,安装相关声明文件。
npm i --save-dev @types/terser-webpack-plugin
在baseConfig
的入口属性中,添加一个better-draggable-ball.min
,作为压缩版的文件。
entry: {
'better-draggable-ball': './src/components/better-draggable-ball/index.ts', // better-draggable-ball 插件
'better-draggable-ball.min': './src/components/better-draggable-ball/index.ts', // better-draggable-ball 插件(压缩版本)
},
// ... ...
在baseConfig
中添加optimization
对象,将含有min
的文件进行压缩处理。
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: 4,
include: /\.min\.js$/,
terserOptions: {
format: {
comments: false,
},
},
test: /\.js(\?.*)?$/i,
extractComments: false,
}),
],
},
在baseConfig
中添加devtool
属性,是选择一种 source map 格式来增强调试过程。不同的值会明显影响到构建(build)和重新构建(rebuild)的速度 ( 官方解释 )详细配置请阅读 Devtool 配置项
devtool:'cheap-module-source-map',
配置完之后,执行npm run build
将项目进行打包 ~ ~
拿打包后的commonjs
版本的插件对比一下,压缩版本(min.js)比未压缩版本减少了约50%的体积,这大大提升了浏览器加载该插件的速度。
关于生成后的map文件
Source map就是一个信息文件,里面储存着位置信息。也就是说,转换后的代码的每一个位置,所对应的转换前的位置。有了它,浏览器开发者工具会调用 source map 来帮助解析,在出错的时候,除错工具将直接显示原始代码,而不是转换后的代码。这无疑在调试过程中带来了很大方便。
这是因为上面的配置文件设置了devtool
devtool: 'cheap-module-source-map'
最后
本系列的教程也到此结束了,很感谢大家的观看,希望这三篇文章对大家有所帮助!
如果你对文章有什么建议可以留言在评论区哦
?? 关注我,不迷路! ??
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!