组内负责的几个项目都有一些一样的公共组件,所以就着手搭建了个公共组件开发脚手架,第一次开发 library,所以是参考着 iview 的配置来搭建的。记录如何使用webpack4搭建一个library的脚手架
使用 webpack4,需要安装 webpack 和 webpack-cli
yarn add webpack webpack-cli -D
然后就是书写配置文件。
我写的 library 的目录结构如下,仅供参考,主要是模仿 iview 的结构,其中部分配置参考了 vue-cli的 webpack 配置文件。
├─build
│ build.js // 用于执行构建
│ check-versions.js // vue-cli 留下的,主要就是检查npm版本和node版本
│ webpack.base.conf.js // 通用配置
│ webpack.dev.conf.js // 开发环境
│ webpack.dist.prod.conf.js // 用于生成library的代码 -- hbf.min.js
│ webpack.prod.conf.js // 用于生成example文件的打包代码,这个其实是没有必要的.
│
├─dist
│ └─example // example生成的打包文件夹,可以通过githubPage来预览,或者本地使用anywhere预览
│ hbf.min.js // library 文件
│
├─example // example目录
│ App.vue
│ index.html
│ main.js
│
├─lib
│ │ index.js // 全量引入公共组件,并暴露出来,包含install方法可供vue引入使用该插件
│ │ README.md
│ │
│ └─components // 公共组件
│
├─package.json // 项目包依赖
更加具体的信息可以到github仓库阅览。
为了更好的理解,先来了解下 webpack 编译后的代码。
经过webpack处理过的代码通常都是如下所示
// webpack编译后的代码
/*
* @param {Array} modules
*/
;(function(modules) {
function __webpack_require__(moduleId) {
var module = {
i: moduleId, // 模块ID
l: false,
exports: {}, // 作为结果返回.
}
// 调用modules数组的某个元素(类型为函数)
modules[moduleId].call(
module.exports,
module,
module.exports,
__webpack_require__
)
return module.exports
}
return __webpack_require__(0)
})([
/** 省略了代码, 该数组的每一项代表一个模块,实际是一个函数,接受三个参数,module对象,module.exports对象,__webpack_require__函数 **/
])
webpack 编译后的代码的整体结构就是一个IIFE函数,接受一个 modules: Array参数。
对于模块处理,无论是 ES Module 的 import 还是 commonjs 的 require 都转化为__webpack_require__ 这个函数来引入模块。
__webpack_require__ 函数,会从 modules 数组的第一个元素开始(moduleId 为 0,也就是入口文件),执行该模块(实为一个函数)的逻辑,利用传入的module.exports的数据类型为引用类型Object,间接地给module.exports添加属性。
return __webpack_require__(0)
从入口文件开始,逐个引入依赖模块,最后返回入口模块的 module.exports
此时这个编译后的 js 文件,是无法被其他模块所引用的,只在当前作用域内有效, webpack 就提供了创建 library 的方式,就是在output里定义library 和 libraryTarget。使得构建完的 js 可以供其他模块引入使用。
对于作为一个 library 使用的项目来说,output 选项需要设置 library
// webpack.dist.pord.conf.js
output: {
path: path.resolve(__dirname, '../dist'),
publicPath: '/dist/',
filename: 'hbf.min.js',
library: 'hbf',
libraryTarget: 'umd'
},
library 可以是字符串,也可以是对象,(对象仅限于 libraryTarget 的值为 umd 的情况下使用)
output: {
library: {
root:'Hbf', // 暴露给全局变量,window.Hbf进行调用
commonjs: 'hbf-public-components'
},
libraryTarget: 'umd'
}
commonjs 和 commonjs2 的区别。
commonjs 规范就是定义了一个 exports 对象,而 nodejs 在实现的时候,在 commonjs 规范的前提下做了一些扩展,定义了 module.exports ,从而也叫这种为 commonjs2 规范。
我们在引用别人的库的时候,通常都是可以通过多种方法引入的,比如 <script> 标签引入,通过 commonJS模块 引入,通过 ES6 Module 引入。
libraryTarget设置为umd(通用模块规范)的话,则打包后可以通过多种模块加载的方法加载 library,具有高兼容性。 关于libraryTarget详细要点可以参考webpack官方文档
如果我们的 library 是基于某某库的基础上开发的,比如说写一个基于vue的 UI 组件库,在开发的这个组件库的时候,我们需要引入vue,如果使用这个组件库的用户本身就已经引入了vue,那么vue就会被引入并打包两次,所以我们在开发一个library的时候,对于一些所依赖的模块,可以由引入library的使用者提供。所以我们需要将依赖的模块在 library 的打包构建中去除。
externals 的作用,防止将某些 import 的包打包到 bundle 中,而是在运行时再去外部获取这些扩展依赖。
通过设置 externals,从输出的 bundle 中排除 vue 和 iview。
这些外部依赖可能是以下的任何一种形式。
// webpack.dist.pord.conf.js
externals: {
vue: {
root: 'Vue',
commonjs: 'vue',
commonjs2: 'vue',
amd: 'vue'
},
iview: {
root: 'iView',
commonjs: 'iview',
commonjs2: 'iview',
amd: 'iview'
}
},
另外在 package.json 加多一个peerDependencies字段,作用是约定library所依赖的库的版本号,在使用者下载使用library的时候,如果所依赖的 iview 和 vue 的版本号不对,就会发出警告。
// package.json
"peerDependencies": {
"iview": ">2.0.0",
"vue": ">2.0.0"
},
对于这两个依赖,写到开发环境依赖中 ,不然安装时,会在库的目录下安装vue 和 iview,这也不符合让 library 的引用者提供 library 的依赖这个想法。
对于 vue 的插件库 / 组件库来说,如果想要全局引入的话,需要有一个install方法。install 内部逻辑就是通过参数传进来的vue对象,注册所有组件。然后最后将所有公共组件连同install方法组成一个新对象暴露出去。
// 引入公共组件
import publicMenu from './components/public-menu'
import tablePage from './components/table-page'
import sliderCustom from './components/slider-custom'
const components = {
publicMenu,
tablePage,
sliderCustom,
}
const Hbf = Object.assign({}, components)
const install = function(Vue, opts) {
if (install.installed) return
Object.keys(components).forEach(component => {
Vue.component(component, component)
})
}
// 用于script标签引入
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
// 将install方法赋给Hbf对象
Hbf.install = install
// 输出default变量,用于全量引入,也可以在引入的时候选择使用 * 来全量引入
export default Hbf
// 输出各个组件,用于按需引入
export { publicMenu, tablePage, sliderCustom }
在暴露含有 install 方法的对象时,一开始使用的是 module.exports,引用 library 的时候报错Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'。
因为我测试用的项目关闭了 babel 对 ES Module 的编译,通常情况下,没有手动关闭的话,babel 会将 ES6 Module 编译转换成 commonjs 规范。所以在关闭了module的转换的情况下,由于库的输出使用的是 commonjs 规范的 module.exports,而引入库使用的是 ES6 模块规范的import关键字,所以产生了报错,我将库的导出写成export关键字,就没报错了。
了解到了现在大多数库,都是用的 commonjs 规范,由于 webpack 的 tree-shaking 只对 ES Module起作用。而webpack 的 tree-shaking 实际上是由Uglylify来实现的。
所以库的模块规范可以使用两种,利用 package.json的 main 和 module 字段分别定义库的两种模块规范的入口文件。 main 使用的是 commonjs 规范语法书写的文件,而 module 是使用 ES6 module 语法书写的文件,module字段目前还是一个提案。所以采用了 ES2015 模块语法的库的,当我们只使用到 library的部分代码,则可以利用webpack 进行 tree-shaking,去除未引用的代码,减少打包文件体积。
首先就是需要注册一个 npm 账号。
如果之前使用的是淘宝镜像的话,需要先切回 npm 官方源。不然是发不了包的。
打开命令行
切换官方源 npm config set registry https://registry.npmjs.org/
执行npm login,然后输入你的账号信息。
可以配置.npmignore 忽略一些不需要上传的文件,写法跟.gitignore 相同。
需要保证项目有正确的package.json文件和README.md文件
然后执行npm publish进行发包。
发完包就可以切回淘宝镜像源
npm config set registry https://registry.npm.taobao.org
一开始是将 JS 文件放在本地测试,发现在HTML文件的第一行就报错,Unexpected token <,StackOverflow说的原因是引入路径不正确,所以我就把 JS 文件放到 CDN 上了,
<script src="http://osuuzm0m8.bkt.clouddn.com/hbf.min.js"></script>
<script>
console.log(window.Hbf) // 会看到你导出的对象
</script>
输出
可以像使用其他 vue 插件库/组件库一样使用。
import hbf from 'hbf-public-components'
// 使用use方法触发hbf的intall方法,注册全部组件
Vue.use(hbf)
如果是没有导出default变量,则使用另外一种方式全量引入
import * as hbf from 'hbf-public-components'
import { publicMenu } from 'hbf-public-components'
按需引用,如果 library 使用的是ES2015 Module规范,则不需要安装任何插件,webpack 会对其进行tree-shaking,去除未引用的代码。
前面提过,webpack的tree-shaking是由Uglylify插件实现的,我在开发环境下,没有启用Uglylify来压缩代码,所以查看模块打包图,会发现整个库都被引入了,虽然我只引入了一个组件。webpack4在生产环境下,才会进行tree-shaking,设置mode的值为production就会开启生产环境下的优化。
如果是使用 commonjs 规范的 library 则需要一个插件支持,babel-plugin-import。该插件是ant官方开发的。许多 UI 组件库的按需引入也是依赖于这个插件。
安装
yarn add babel-plugin-import -D
修改.babelrc文件,
"plugins": [
["import", {
"libraryName": "hbf-public-components",
"libraryDirectory": "lib/components"
}]
],
其实如果对于一个不是很稳定,需要一直迭代更新的公用组件库来说,使用 npm 包的话,会比较不方便,经常更新的公共组件代码可以使用Git subtree(教程)来维护,可以等到一定地步之后,公共组件库稳定下来之后再考虑发布一个 npm 包。
而开发一个组件库,也可以使用 rollup.js 来搭脚手架,rollup.js 默认使用的就是 ES2015 Module,可以进行静态分析,去除未引用的代码,tree-shaking 也是 rollup.js 先提出的。Rollup相比较于Webpack,更适合用于构建library,Vue.js就是使用 Rollup 构建的。Webpack 在代码分割这方面比较有优势,所以webpack 相对来说比较适合构建应用程序,不过使用 webpack 构建 library 也是可以的。
这个项目也可以用做 webpack 构建 library 的通用脚手架。下次再尝试Rollup构建 library
一项名为 JavaScript 功能的提案 Array.prototype.flatten 证明与 Web 不兼容。在 Firefox Nightly 中发布该功能会导致至少一个受欢迎的网站中断。鉴于有问题的代码是广泛使用的 MooTools 库的一部分,很可能会有更多网站受到影响。
让你了解到新兴和酷炫的web 开发趋势. 精心挑选发布一些认为大家值得关注的库:Direction Reveal、Carbon、Аxios、Jarvis、Toast UI Editor、Micron.js、lit
math.js是一个广泛应用于JavaScript 和 Node.js的数学库,它的特点是灵活表达式解析器,支持符号计算,内置大量函数与常量,并提供集成解决方案来处理不同的数据类型,如数字,大数字,复数,分数,单位和矩阵。
当你调研一个 JS 库,功能当然是最重要的。作者给出了从 12 个角度全面分析 JS 库的可用性,分别是:特性,稳定性,性能,包生态,社区,学习曲线,文档,工具,发展历史,团队,兼容性,趋势
对于今年的JavaScript状态调查,我想深入挖掘一下,不仅知道人们正在使用哪些工具和库,还要为什么他们选择使用它们。这意味着我必须找到一种方法将个人偏好转化为冷酷的数据。
本篇 React native 库列表不是从网上随便找的, 这些是我在我的应用中亲自使用的库。 这些库功能可能跟其它库也有,但经过大量研究并在我的程序中尝试后,我选择了这些库。
我们的使命是让您了解最新和最酷的Web开发趋势。下面为大家分享10个有趣的javascript和css库:Tessaract.js强大的javascript(节点和浏览器)库,用于从图像中提取文本。
在javascript的帮助下,可以为几乎每个领域(如移动、桌面应用程序和游戏Web开发)创建Web应用程序,因为该编程语言用作服务器端编程语言以实现最大功能,所以它是一种很好的编程语言。在本文中,我们选择了一些最佳的javascript库汇总
当我想要在网上找一个简洁的 Javascript 动效库时,总是发现很多“推荐”的库都是缺乏持续维护的。经过一番研究,我收集了 11 个最好的库,你可以用在自己的项目中。另外我还添加了一些有用但是缺少持续维护的库
如今 Vue 的热度不断攀升,使用者越来越多,Vue.js 工具也随处可见。这种现象不是凭空产生的:Vue 的学习曲线友好,功能驱动的结构清晰易懂,文档出色易学,所以新人入门很容易,经验丰富的开发人员也可以快速从其他框架
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!