约定大于配置的极速 Web 应用打包工具,支持 .vue 文件,生产使用 Rollup 打包
仅供学习研究,请勿用于生产
【Github】 https://github.com/chjtx/pr1
【 码 云 】 https://gitee.com/chenjianlong/pr1
对比环境 华为荣耀 MagicBook Windows 10 家庭版 i5 8G 64位 联通4G热点 30多个组件的小型 Vue 项目
飘刃 | Vue-CLI | |
---|---|---|
工具版本 | piaoren@0.1.1 | @vue/cli@3.6.3 |
依赖包数 | 487 | 689 |
安装命令 | npm i -g piaoren | npm i -g @vue/cli |
安装时间 | 38s | 1m 42s |
支持编码 | Pug Sass ES6+ | Pug Sass Less Stylus ES6+ TypeScript |
创建项目 | pr1 init 只需要填项目名称 | vue create/vue init 需要填选多项 |
启动命令 | pr1 start | vue serve |
启动时间 | 2s 与项目内容多少无关 | 6.8s 项目内容多少决定 |
热更响应 | 支持更新 css 和刷新页面 两种方式,不支持 js 更新 更新 js 需要刷新页面 响应速度 立即 |
支持 css 和 js 更新,vue 组件更新 有点鸡肋,很大概率需要手动更新 才能看到预期效果,每次变化都需 要编译,响应速度 稍慢 |
打包工具 | Rollup | Webpack |
打包时间 | 5s 项目内容多少决定 | 10s 项目内容多少决定 |
静态资源 | 暂只支持. 和/ 开头的静态资源 |
支持. 、/ 、@ 和~ 开头的静态资源 |
多页应用 | 无需配置 | 需要配置 pages |
插件支持 | Rollup 插件规范 | Webpack 插件规范 |
单元测试 | 暂不支持 | 可选 |
总结:飘刃安装时间、启动速度、响应速度、打包时间都优于 Vue-CLI,但是配置方面不及 Vue-CLI 丰富。中小型无需配置的项目选择飘刃,大中型需要多方面资源配合的项目选择 Vue-CLI。
npm i -g piaoren
把飘刃安装到全局,任意目录都可以运行飘刃的命令 pr1
pr1 init
? Project name: # 项目名称至少两个字符,由大小写字母、中划线、下划线,及数字组成,数字不能为首字符
? Project description: # 可不填
将会自动生成项目名称命名的文件夹,包含若干工程文件
进入工程目录,执行以下命令开启开发模式
npm run dev
// main.js
import Vue from 'vue/dist/vue.esm.browser.js'
import Layout from './pages/Layout.vue'
// eslint-disable-next-line no-new
new Vue({
el: '#app',
components: {
Layout
},
template: '<Layout/>'
})
<!-- pages/Layout.vue -->
<template lang="pug">
div
div.top
input(v-model="text")
button(@click="submit") 添加
ul
Item(v-for="(i, k) in items" :name="i" :key="k")
</template>
<script>
import Item from './Item.js'
export default {
components: {
Item
},
data () {
return {
text: '',
items: []
}
},
methods: {
submit () {
this.items.push(this.text)
this.text = ''
}
}
}
</script>
<style lang="sass" scoped>
$bg: #ccc;
.top {
padding: 20px;
background: $bg;
}
</style>
// pages/Item.js
import html from './Item.html'
export default {
template: html,
props: {
name: String
}
}
<!-- pages/Item.html -->
<li class="item">{{ name }}</li>
<style scoped>
.item {
background: #eee;
}
</style>
在浏览器访问 http://localhost:8686/
以上例子演示了两种写 Vue 组件的方法
一、使用 .vue 文件,目前 .vue 文件只支持普通的 html/css/js 和 sass/pug ,不支持 less/typescript 等。注意 Layout.vue 的 pug ,首行第一个位置不能是空格,即不能缩进。
二、使用 html 和 js 两个文件写 Vue 组件,如果存在同路径同名的两个文件,例:Component.html 和 Component.js,则飘刃会把这两个文件处理成 Vue 组件。需要注意的是,这种方式的 html 文件不包括 script ,所以不需要 template 标签,直接写 div ,也不支持 pug。
开发完成后,使用以下命令打包
npm run build
打包完成后可在 dist 目录双击 index.html 到浏览器访问,如果项目包含 ajax 请求,file:// 协议文件无法跨域,可以在 dist 目录运行 pr1 start 8080 开启飘刃服务,在浏览器访问 http://localhost:8080/
# 创建项目,初始化工程文件
pr1 init
# 开启飘刃服务,在哪个目录开启,哪个目录就是根站点
# 可在浏览器访问该站点文件,相当于微型静态服务器
# 将会拦截所有带 pr1_module=1 参数的 url 进行文件处理
# 用于开发环境
pr1 start [port] [config]
# 示例
pr1 start # 默认 8686 端口,工程根目录的 pr1.config.js 配置文件
pr1 start 8080 # 指定 8080 端口
pr1 start --config="./config.js" # 指定 ./config.js 配置文件
pr1 start 8080 --config="./config.js" # 指定端口和配置文件
# 使用 build 命令打包,必须指定入口文件,只能是 html 和 js 文件
# 可以同时打包多个模块
# 如果是 html 文件,将会自动解决 html 里的入口文件及复制静态资源
# 如果是 js 文件,只会解决该 js 文件及其依赖,不会复制静态资源
# 入口文件目录与打包后的文件目录结构相同
pr1 build [entry] [config]
# 示例
pr1 build index.html # 使用默认配置文件打包
pr1 build index.html --config="./config.js" # 使用指定配置文件
pr1 build index.html detail.html tools.js # 同时打包3个文件
pr1 build index.html detail.html tools.js --config="./config.js" # 使用指定配置打包3个文件
pr1 build page1/index.html page2/index.html # 在打包后也会保持同样结构
// pr1.config.js
const nodeResolve = require('rollup-plugin-node-resolve')
require('colors')
module.exports = {
// vendor 子项的第一个值将会整合到 rollup 的 external
// [0]是开发环境用的,[1]是生产环境用的,如果没有[1]生产环境也用[0]
vendor: [
['vue/dist/vue.esm.browser.js', 'vue/dist/vue.runtime.min.js']
],
// true 表示存在同级目录且同名的 html 和 js 文件会被关联到一起
// 转成 Vue render 组件提高性能,仅生产环境起作用
html2VueRender: true,
// 热更新 true or reload,如果是字符串 reload,将会刷新浏览器而非 .vue 组件
hot: true,
// dist 打包后文件输出目录,路径应相对于当前配置文件
dist: '',
// static 静态文件,路径应相对于 html 入口文件
static: [],
// rollup 选项,必须有
rollupConfig: {
// 定义了 vendor,再定义 globals,这样 rollup 会把相关的 vendor 转换成全局变量作为外部资源处理
globals: {
'vue/dist/vue.esm.browser.js': 'Vue'
},
plugins: [
// rollup-plugin-node-resolve 用于解决引用 node_modules 资源路径
nodeResolve()
]
},
// babel 选项,不提供将不会进行转码,不使用 uglify 压缩时,可安装 babel 的 minify 插件压缩
babelConfig: {
presets: [
[
'@babel/env', {
modules: false,
targets: {
ie: '9',
chrome: '49'
}
}
]
]
},
// uglify 选项,不提供将不会压缩,如果 babel 转码后仍存在 ES6+ 代码,uglify 解释不了将会压缩失败
uglifyConfig: {
toplevel: true
},
// 打包前的钩子
beforeBuild: async function (originDir) {
console.log(`开始打包:`.green + `${originDir}`.cyan)
},
// 打包后的钩子
afterBuild: async function (distDir) {
console.log(`完成打包:`.green + `${distDir}`.cyan)
}
}
飘刃会拦截所有带有 pr1_module=1 参数的 url ,并处理对应的文件资源,目前只会处理 .vue .html .js 3种文件
把 import/export 转换成 async/await 让浏览器可以支持引入除 js 外的其它资源
飘刃会把非 js 资源通过 rollup 的插件转换成 js 资源再传到浏览器,开发环境只会调用 rollup 插件的 resolveId
和 transform
方法
import/export 转换关系如下:
// import 规则
import { a, b, c } from './util.js' => const { a, b, c } = await _import('./util.js')
import { abc as a, efg as b } from './util.js' => const { abc: a, efg: b } = await _import('./util.js')
import a from './util.js' => const { default: a } = await _import('./util.js')
import './util.js' => await _import('./util.js')
import * as a from './util.js' => const a = await _import('./util.js')
import a, { efg as b, c } from './util.js' => const { default: a, efg: b, c } = await _import('./util.js')
// export 规则
export var a = 'xxx' => var a = exports.a = 'xxx'
export { a, b, c } => Object.assign(exports, {a, b, c})
export function a () {} => exports.a = a; function a () {}
export default a => exports.default = a
export { abc as a } => Object.assign(exports, {a: abc} = { a })
export class e {} => exports.e = e; class e {}
export { default as d } from './util.js' => Object.assign(exports, await (async () => { const { default: d
} = await _import('./util.js'); return { d }})())
支持两种静态资源路径 以 /
开头和以 .
开头
/
开头的资源路径相对站点根目录.
开头的资源路径相对当前引用的文件如下目录结构
src/
|-- index.html
|-- static/
|-- images/
|-- a.png
|-- pages/
|-- one/
|-- two/
|-- three/
|-- a.vue # background-url: /static/images/a.png
|-- b.html # img src="../static/images/a.png"
|-- b.js
绝对路径和相对路径都是引用同一张图片
支持组件多 style ,组件内 style 均为组件内样式,带 scoped 不会影响子组件,不带 scoped 会影响子组件,全局样式请用 link 标签引入
飘刃处理多面应用非常简单,如下目录结构
src/
|-- page1/
|-- index.html
|-- page2/
|-- index.html
|-- page3/
|-- index.html
开发环境,在 src 目录执行 pr1 start
在浏览器分别访问
生产环境,在 src 目录执行 pr1 build page1/index.html page2/index.html page3/index.html
在 dist 目录会保持以下目录结构
dist/
|-- page1/
|-- index.html
|-- page2/
|-- index.html
|-- page3/
|-- index.html
目前只支持引入 .ts 文件,.vue 组件的 type=ts 暂不支持
# 安装
npm i rollup-plugin-typescript typescript tslib
修改 pr1.config.js 添加 typescript 插件
const typescript = require('rollup-plugin-typescript')
// ...
module.exports = {
rollupConfig: {
// ...
plugins: [
typescript({
target: 'ESNext',
})
// ...
]
},
// ...
}
如下示例:
doSome(data => {
// pr1 ignore++
console.info(`调试信息:${data}`)
// pr1 ignore--
doIt(data)
})
// pr1 ignore++
到// pr1 ignore--
的代码在生产环境会被删除
doSome(data => {
doIt(data)
})
rollup-plugin-node-resolve
插件解决@import
导入是相对于当前 sass 所在文件的,只支持 @import sass,暂不支持自动拷贝 @import css 的文件<style lang="sass" scoped>
、<style lang="sass">
、<style scoped>
,不允许<style scoped lang="sass">
,同理如果要使用 pug ,必须书写成<template lang="pug">
,不允许多空格或少空格<template>
<div class="top">
<div class="abc">123</div>
</div>
</template>
<style>
/* 不带 scoped 必须使用 this 表示最外层 dom 选择器 */
this {
background: #efefef;
}
.abc {
font-size: 20px;
}
</style>
<style scoped>
/* 带 scoped 可以使用最外层 dom 的 class 来做选择器 */
.top {
font-size: 22px;
}
</style>
如果同目录存在同名的 html 和 js 文件并开启 html2VueRender
选项,默认开启,则视为 Vue 组件,打包时会自动关联转成 render 函数。同名 js 文件只能用 template: html,不能用其它变量
// html/js 的 Vue 组件只能用 html 作为变量名引入同名 html 文件
import html from './sameName.html'
export default {
template: html
}
在 html 里的 <img src="./..">
和 css 里的 background:url(./..)
小于 4k 的图片会自动转为 base64,无法自动解决的静态资源需要手动在 static 选项添加资源目录名或具体资源文件名,如下示例的资源不能自动处理
<img v-for="i in images" :src="i.src">
js 文件或 vue 文件如果在行首要输入 import xxx from
export default
这类字符串需要转义,或者使用字符串拼接不能让飘刃转换 import 和 export 的规则命中
const str = `
import xxx from 'a.js'
export default { b: 1 }
`
// 要写成
const str = `
\u0069mport xxx from 'a.js'
\u0065xport default { b: 1 }
`
// 或
const str = `
i` + `mport xxx from 'a.js'
e` + `xport default { b: 1 }
`
运行 pr1 start
出错
Error: listen EADDRINUSE :::8686
at Server.setupListenHandle [as _listen2] (net.js:1335:14)
at listenInCluster (net.js:1383:12)
8686 端口被占用,解决方案:指定端口运行或先关闭占用 8686 端口的程序
运行 pr1 build
出错
(node:20976) UnhandledPromiseRejectionWarning: Error: EBUSY: resource busy or locked, rmdir 'D:\xx\dist'
dist 目录繁忙或锁定,无法删除。解决方案:检查 dist/index.html 是否在浏览器中打开,将其关闭再重新打包
### v0.3.16 (2020-04-11)
exports { default } from 'xxx'
解释报default
是保留字的错误问题### (2019-12-30)
v0.3.15
class a extend b
格式解释错误的问题v0.3.14
export * from 'xxx'
格式module.exports=
exports 被修改的问题export { a, b as bb }
带有 as 和无 as 混合格式导出### v0.3.13 (2019-12-07)
### v0.3.12 (2019-10-29)
### v0.3.11 (2019-10-04)
### v0.3.10 (2019-08-12)
pr1 start
报错的问题### v0.3.9 (2019-06-28)
### (2019-06-02)
v0.3.8
export const a =
在本文件不起作用的 bugv0.3.7
v0.3.6
添加模块 rollup-plugin-paths 路径别称支持
添加支持 node_modules 模块无后缀名资源的引入
修复 export {
以 { 结尾的导出语法解释错误
修复文本内容带 $&
$$
等特殊字符替换文本出错的 bug
### v0.3.5 (2019-05-26)
### (2019-05-25)
v0.3.4
v0.3.3
### (2019-05-24)
v0.3.2
v0.3.1
### v0.3.0 (2019-05-23)
### (2019-05-22)
v0.2.13
v0.2.12
v0.2.11
hot: 'style'
选项### v0.2.10 (2019-05-12)
export default Vue.extend({
等语法### v0.2.9 (2019-05-08)
### (2019-05-06)
v0.2.8 修复 v0.2.1 优化项目文件结构产生引用 某些 js 路径错误的问题
v0.2.7
### v0.2.6 (2019-05-04)
export function abc
开发阶段同文件其它函数访问不了 abc()
的问题### (2019-05-02)
### v0.2.1 (2019-04-30)
resolveId
方法### v0.2.0 (2019-04-29)
import a, { b, c } ...
和 export { a } from ...
语法@import
导入路径问题### v0.1.1 (2019-04-26)
### v0.0.10 (2019-04-24)
支持作者继续维护更新,编写更多教程和使用技巧。如果有足够的支持,飘刃将来将会支持 React、TypeScript、异步模块等等。
支持方式
打赏1块几毛钱,让作者不用去天桥底蹲位
MIT
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
1. 开源生态
2. 协作、人、软件
3. 评估模型