文章目录

  • tinymce 环境搭建
    • 初始化目录结构
  • 使用 Rollup 运行,打包
    • Rollup 打包效果
    • 新建 2 个插件,编写 rollup.config.js
    • rollup 配置 ES6 转 ES5
    • rollup 配置 代码压缩
    • 添加 serve 和 热更新
    • rollup 支持 less
    • 打包配置
    • 动态入口
    • 根据目录打包
    • 引入静态资源 和 清理旧资源
  • 最后

先介绍一下这个系类(tinymce),该系列以后相关的代码都会更新在 tinymce-plugins

tinymce 是一个富文本插件。官网已经介绍的很清楚了

这个系列主要的目的就是把在工作中遇到的 tinymce 遇到的坑和一些插件开发流程记录下来(毕竟网上这部分资料真的太少了。。。)

tinymce 环境搭建

tinymce 使用是非常简单的,官网也有很详细的介绍(一些简单非必要的配置我就不细说了)

这里的环境搭建并不是 tinymce 的源码环境或者只是单纯运行 tinymce,而是为了开发 tinymce 配套插件准备的环境。所以就从环境搭建先开始吧

之前尝试过用 webpack。失败了,或许是实力不够把~

所以下面会介绍使用 rollup 来搭建:rollup 源文档、rollup 中文文档

接下来使用的版本是 tinymce@5.2.0

注意下载的是 dev 版本,因为后续有看源码的需要~

初始化目录结构

下载了 Dev 的代码后,源码部分都在 modules 文件夹里面的,搭建环境要用的 JS 隐藏的比较深,找到有 tinymce.min.js 的文件夹的上一层。就是我们要引入的 JS 了

目录结构如下:红色框中的就是 tinymce 的代码,剩下的我们自己新建一个 index.html

  • index.html 内容

如果需要配置 language ,需要自己下载对应的中文包,我这里就不管他了。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>tinymce 插件开发环境</title><script src="./js/tinymce/tinymce.min.js"></script></head><body><textarea class="tinymce" style="height:90vh;" id="tinymce"> </textarea></body><script>tinymce.init({selector: 'textarea.tinymce',plugins: 'code advlist lists advlist',toolbar: 'undo redo | advlist fontsizeselect lineheight',setup(editor) {}})</script>
</html>

这时候直接打开 index.html 或者用 http-server 运行可以看到如下:

使用 Rollup 运行,打包

webpack 和 rollup 都是打包工具,打包配置并不难。
可是每次看完教程自己打包都会踩坑,那是因为每个时期的依赖包版本的问题 = =。 这才是打包的最大障碍

添加 2 个运行命令,用于运行和打包的。

rollup 号称是无须配置文件都可以打包的,具体可以看下官网 rollup 命令

这里我就只在 serve 环境下使用 -c--watch 功能。

-c 可以指定配置文件入口。–watch 监听文件变化

从运行命令看得出,我们要建一个 build/rollup.config.js

为了减少踩坑过程,直接贴出我的依赖包配置(尤其是 babel)

{"scripts": {"serve": "cross-env NODE_ENV=development rollup -c build/rollup.config.js --watch","build": "cross-env NODE_ENV=production rollup -c build/rollup.config.js"},"devDependencies": {"babel-preset-es2015-rollup": "^3.0.0","babel-preset-stage-0": "^6.22.0","cross-env": "^7.0.3","less": "^4.1.2","livereload": "^0.9.3","postcss": "^8.3.9","rollup": "^2.58.0","rollup-plugin-babel": "^2.7.1","rollup-plugin-clear": "^2.0.7","rollup-plugin-commonjs": "^10.1.0","rollup-plugin-copy": "^3.4.0","rollup-plugin-livereload": "^2.0.5","rollup-plugin-postcss": "^4.0.1","rollup-plugin-serve": "^1.1.0","rollup-plugin-uglify": "^6.0.4","rollup-watch": "^3.2.2"}
}

Rollup 打包效果

这个配置要达到什么效果?

  • 因为后续我们开发的插件可能不止一款,那么就会有多入口多出口的打包需求
  • tinymce 正式环境加载的都是 .min.js 文件。所以要有一个压缩 JS 的功能
  • 很多插件有可能不一定满足我们样式需求,还得支持使用 .less
  • ES6 转 ES5
  • 支持 server,运行后打开 localhost:8080
  • 支持热更新

新建 2 个插件,编写 rollup.config.js

根据 tinymce 的插件目录要求

  1. 插件都在 js/tinymce/plugins/
  2. 以插件名命名文件夹
  3. 对应插件文件夹下有 plugin.jsplugin.min.js。tinymce 会自动选择是加载 .js 或 .min.js。

所以测试插件目录如下:

使用的话打开 index.html。在初始化 tinymce 的代码中改为如下(在 plugins 加入 myplugins myplugins2):

tinymce.init({selector: 'textarea.tinymce',plugins: 'code advlist lists advlist myplugins myplugins2',toolbar: 'undo redo | advlist fontsizeselect lineheight'
})

看到插件有正常加载

然后就是 rollup.config.js 的配置了

  • build/rollup.config.js

配置的雏形,因为是多入口多出口,所以只能导出一个数组的配置了

format 需要提一下就是打包为iife ,就是立即执行函数。等下就能看到效果了
其他输出的类型:(amd, cjs, esm, iife, umd)

当然还有其他的配置,

const path = require('path')
const pluginsPath = path.resolve(__dirname, '../src/js/tinymce/plugins/')export default [{input: path.join(pluginsPath, 'myplugins/plugin.js'),output: {format: 'iife',file: path.join(pluginsPath, 'myplugins/plugin.min.js')}},{input: path.join(pluginsPath, 'myplugins2/plugin.js'),output: {format: 'iife',file: path.join(pluginsPath, 'myplugins2/plugin.min.js')}}
]

然后运行npm run serve,来启动这份配置。看到下面的效果就是生效了

rollup 配置 ES6 转 ES5

上面的效果可以看出 format 已经生效了,把我们的函数打包为立即执行函数。但也真的仅仅是打包为立即执行函数,如果我们写一些 ES6 语法,并不会转换

接下来用到 2 个库(如果上面和我一样已经直接配置好 package.json 的就不用重复安装了)

  • rollup-plugin-babel ES6 转 ES5 插件

  • babel-preset-stage-0

  • babel-preset-es2015-rollup

  • rollup-plugin-commonjs 将 CommonJS 模块转换成 ES6,防止他们在 Rollup 中失效;

import babel from 'rollup-plugin-babel' // ES6转ES5插件
import commonjs from 'rollup-plugin-commonjs' // 将CommonJS模块转换成ES6,防止他们在Rollup中失效;export default [{input: path.join(pluginsPath, 'myplugins/plugin.js'),output: {format: 'iife',file: path.join(pluginsPath, 'myplugins/plugin.min.js')},plugins: [// 添加插件配置commonjs(), // es6 转babel({babelrc: false, //不设置.babelrc文件;exclude: 'node_modules/**', // 忽略 node_modules 目录(虽然我们也用不上 node_modules)presets: ['es2015-rollup', 'stage-0'], //转ES5的插件;plugins: ['transform-class-properties'] //转换静态类属性以及属性声明的属性初始化语法})]}// ....
]

重新运行,发现语法已经有转义了

rollup 配置 代码压缩

既然是 .min.js 那压缩少不了

涉及的插件包就是 rollup-plugin-uglify

import { uglify } from 'rollup-plugin-uglify' // js压缩
export default [{// ...plugins: [// ...uglify()]}
]

是不是感觉配置特别简单?!就引入插件,在 plugins 目录执行方法就行了

rollup-plugin-uglify 注意下版本的问题,就版本引入是 import uglify from 'rollup-plugin-uglify'。如果用的是我的版本的话,需要通过解构赋值来引入。

重新运行就能看到效果了

添加 serve 和 热更新

  • rollup-plugin-serve
  • rollup-plugin-livereload
  • livereload

注意有些包不一定是要引入的,比如 livereload 就不需要引入,不过 rollup-plugin-livereload 依赖了这个包,所以才需要装

关于 serve 的配置,可以看下: npm - rollup-plugin-server

import serve from 'rollup-plugin-serve' // serve服务
import livereload from 'rollup-plugin-livereload' // 热更新// 引入一个新变量
const srcPath = path.resolve(__dirname, '../src/')export default [{// ...plugins: [// ...serve({open: true, // 自动打开浏览器verbose: true, // 在终端输出打开的链接contentBase: srcPath, // 项目入口openPage: '/index.html', // 默认打开的页面port: '8080' // 端口号}),livereload()]},{// ...plugins: [livereload()] // 注意 serve 只要执行一次}
]

server 只需要执行一次,livereload 需要有多少个入口执行多少次

因为 server 启动一个就够了,而多入口监听文件变化,热更新是依赖 livereload 的插件的

看到有自动打开浏览器,那就是配置对了!

看下 plugins.min.js 文件,插件帮我们加了一份热更新代码。

热更新效果 虽然是强制刷新而不是局部更新,可是那也很香了好吗~

rollup 支持 less

不要问为什么不用 scss,其实都是一个道理的

需要的插件包:

  • less
  • postcss
  • rollup-plugin-postcss
import postcss from 'rollup-plugin-postcss'export default [{plugins: [postcss({extensions: ['.less'], // 编译.less 文件extract: true,modules: false,inject: false, // 核心,不要在 html 插入css代码,因为 tinymce 有自己引入css的一套方法minimize: true})// ...]}
]

注意引入顺序

如果我们先处理 js ,然后在处理 css 就会报错。所以我们处理 less 应该提到 plugins 的第一位

还有一个要注意点的是,less 文件必须在 plugin.js 引入,否则 rollup 是不会帮你打包对应的 css 文件的

其次就是,不管你的 less 文件有多少个,因为 output 配置的输出名称是是 plugin.min.js。所以 css 最后都会被合并到 plugin.min.css

可以看到现在是写了 .less 文件完全没反应的,接下来在 plugin.js 引入一下 less import './style/index.less' 就能看到同级目录输出 plugin.min.css

打包配置

至此,基本骨架已经有了。不过上面的配置都是运行 serve 的。我们打包正式的包,肯定不能有热更新之类的代码了,所以针对 npm run build 在做一些修改

  • cross-env 设置环境变量
  • rollup-plugin-clear 清理打包目录

cross-env 在 package.json 文件就有设置了 NODE_ENV

所以我们判断是开发环境/打包只需要判断

const isDev = process.env.NODE_ENV == 'development'

在开发目录 /src/js/tinymce/plugins 里面可能会有很多无关的文件,所以打包我们还需要打包一份到 /dist 目录,方便我们发布版本

对于这种一个文件对应多个出口的,output 支持配置为数组!

当然了,这部分只是伪代码,还需要把 serve 注释掉

const rootPath = path.resolve(__dirname, '../')
const pluginsPath = path.resolve(__dirname, '../src/js/tinymce/plugins/')const isDev = process.env.NODE_ENV == 'development'export default [{input: path.join(pluginsPath, 'myplugins/plugin.js'),output: [{format: 'iife',file: path.join(pluginsPath, 'myplugins/plugin.min.js')},{format: 'iife',file: path.join(rootPath, 'dist/myplugins/plugin.min.js')},{format: 'iife',file: path.join(rootPath, 'dist/myplugins/plugin.js')}]}
]

打包后的效果如下(有几个小问题,样式打包多了,plugin.js 并非未压缩的代码,后面的配置还会继续完善):

动态入口

动态入口其实就是指定目录后,遍历文件夹,然后根据我们的规则生成对应的 inputoutput 就行了

包括之前的一些代码也重新整理下,整理为如下几个:

  • build/getEntry.js
const path = require('path')
const fs = require('fs')module.exports = function(entry) {if (!entry) {console.log('入口目录不存在', entry)process.exit(0)}try {let stat = fs.statSync(entry)if (!stat.isDirectory()) {console.log('入口目录不存在', entry)process.exit(0)}} catch (e) {console.log('入口目录不存在', entry)process.exit(0)}let routes = []fs.readdirSync(entry).forEach(function(item, index) {let pluginFolder = path.join(entry, item)let floderStat = fs.statSync(pluginFolder)// 这里判断是否插件目录if (floderStat.isDirectory()) {try {let plugin = path.join(pluginFolder, 'plugin.js')let pluginStat = fs.statSync(plugin)if (pluginStat && pluginStat.isFile()) {routes.push({path: plugin,floder: pluginFolder,name: item})}} catch (e) {}}})return routes
}
  • build/getPlugins.js
const babel = require('rollup-plugin-babel') // ES6转ES5插件
const commonjs = require('rollup-plugin-commonjs') // 将CommonJS模块转换成ES6,防止他们在Rollup中失效;
const { uglify } = require('rollup-plugin-uglify') // js压缩
const serve = require('rollup-plugin-serve') // serve服务
const livereload = require('rollup-plugin-livereload') // 热更新
const postcss = require('rollup-plugin-postcss')/*** 获取不同配置对应的插件* @param {*} isDev 是否开发环境* @param {*} isFirst 是否第一个入口* @param {*} config 拓展配置* @returns*/
module.exports = function(isDev, isFirst, config = {}) {let plugins = [postcss({extensions: ['.less'], // 编译.less 文件extract: true,modules: false,inject: false, // 核心,不要在 html 插入css代码,因为 tinymce 有自己引入css的一套方法minimize: !config.unUglify}),commonjs(),babel({babelrc: false, //不设置.babelrc文件;exclude: 'node_modules/**',presets: ['es2015-rollup', 'stage-0'], //转ES5的插件;plugins: ['transform-class-properties'] //转换静态类属性以及属性声明的属性初始化语法})]if (isDev) {// 只有第一个才需要serveisFirst &&plugins.push(serve({open: true, // 自动打开浏览器verbose: true, // 在终端输出打开的链接contentBase: config.srcPath || '', // 项目入口openPage: '/index.html', // 默认打开的页面port: '8080' // 端口号}))// dev 都加热更新plugins.push(livereload())} else if (!config.unUglify) {// 打包才压缩jsplugins.push(uglify())}return plugins
}
  • build/rollup.config.js
const path = require('path')const rootPath = path.resolve(__dirname, '../')
const pluginsPath = path.resolve(__dirname, '../src/js/tinymce/plugins/')
const srcPath = path.resolve(__dirname, '../src/')const isDev = process.env.NODE_ENV == 'development'const getEntry = require('./getEntry')
const getPlugins = require('./getPlugins')function run() {let config = []let isFirst = truegetEntry(pluginsPath).forEach(item => {let _output = [{format: 'iife',file: path.join(item.floder, 'plugin.min.js') // 基础目录,打包在 plugins}]if (!isDev) {_output.push({format: 'iife',file: path.join(rootPath, 'dist', item.name, 'plugin.min.js') // 打包目录})}config.push({input: item.path,output: _output,plugins: getPlugins(isDev, isFirst, { srcPath })})!isDev &&config.push({input: item.path,output: {format: 'iife',file: path.join(rootPath, 'dist', item.name, 'plugin.js') // 打包一个不压缩的},plugins: getPlugins(isDev, isFirst, { srcPath, unUglify: true })})isFirst = false})return config
}export default run()

根据目录打包

如果不区分目录,那么 plugins 下内置的插件也是我们的打包对象,显然我们并不用关心这部分代码,所以加一个配置来过滤掉这部分的文件

  • 方法 1 : 写一个配置文件,打包只需要的插件名称
  • 方法 2 : 规范插件命名方式,比如统一加一个 my_ 来区分

所以我采用了方式 2,改一下 build/getEntry.js

改了前缀名的话,相关的引入记得也改一下~

引入静态资源 和 清理旧资源

最后发现一个小问题就是打包 less 的时候并没有帮我们把图片资源打包进入

所以在约定一个:插件下的 assets 目录,虽然不参与打包,但是打包的时候直接把 assets 目录复制一份。这时候引发另外一个问题就是打包后的 less,层级没有自动帮我们改过来,比如下面的情况:

这种情况,只能约定大于配置了~写好文档,css 文件都写插件根目录,然后引入对应 assets 资源。不然这种情况太极端了 (就是懒)

要用到的插件包

  • rollup-plugin-clear

  • rollup-plugin-copy

  • 修改 build/getEntry.js 判断目录是否需要复制 assets

  • 修改 build/getPlugins.js 引入 clear 和 copy 插件

代码就不贴了,看下 gitee 把 tinymce-plugins

最后

至此 tinymce 系列的第一章 tinymce 环境搭建,就搭建好了

以后开发 tinymce 插件也是基于这个环境了~

tinymce系列(一) tinymce 环境搭建相关推荐

  1. win10编译OpenCV4Android系列1-Android编译环境搭建

    win10编译OpenCV4Android系列1-Android编译环境搭建 前言 一.配置JDK 1.下载JDK 2.安装JDK 二.配置AndroidSDKTools 1.下载AndroidSDK ...

  2. 【Hexo搭建GitPage博客系列】02.环境搭建

    转载声明:商业转载请联系作者获得授权,非商业转载请注明出处.原文来自 © 呆萌钟[Hexo搭建GitPage博客系列]02.环境搭建 前言 Hexo搭建博客需要基于Node.js环境,而且依赖于Git ...

  3. 【瑞萨RA4系列】开发环境搭建和点灯指南

    [瑞萨RA4系列开发板体验]开发环境搭建和新手点灯指南 文章目录 [瑞萨RA4系列开发板体验]开发环境搭建和新手点灯指南 一.简单开箱 二.芯片简介 三.开发环境搭建 2.1 安装FSP(RASC) ...

  4. 王姨劝我学HarmonyOS鸿蒙2.0系列教程之一环境搭建跑起来模拟器!

    原创PDF |<Android 深入系统完全讲解>免费开源,可能价值百万! 学习一门新的技术前,我一般会翻看官方文档,源码,以及网上的一些总结,好形成一个初步印象,让开发的时候心中有谱. ...

  5. 【s32k】s32k14x系列(1)——开发环境搭建

    文章目录 s32k1xx环境搭建 1. S32K系列MCU开发环境 2. 软件安装包及SDK获取 3. 软件安装 s32k1xx环境搭建 1. S32K系列MCU开发环境 主要有以下三种环境供我们选择 ...

  6. 涂鸦Zigbee SDK开发系列教程——2.环境搭建

    本章节主要介绍如何搭建涂鸦 Zigbee ZSU 模组 SDK 开发环境. IAR安装 前往 IAR 官网下载 IAR Embedded Workbench IDE(IAR for Arm),下载安装 ...

  7. Xavier NX载板RTSO-6002/E 系列烧录及环境搭建

    http://www.realtimes.cn/cn/product/product-21-889.html realtimes2022 官方资料 使用版本:R32.5.1_for TX2_Xavie ...

  8. stm32 micropython环境搭_MicroPython 玩转硬件系列1:环境搭建

    1.引言 最近几年Python语言非常火,听说小学生都开始学Python了,让我这个中年人感到一丝丝压力.为了以后最起码能辅导辅导孩子,咱也得学学啊.学Python干什么用呢?我这本身是做嵌入式的,听 ...

  9. 学python电脑硬件_Micropython 玩转硬件系列1:环境搭建

    1. 引言 最近几年Python语言非常火,听说小学生都开始学Python了,让我这个中年人感到一丝丝压力.为了以后最起码能辅导辅导孩子,咱也得学学啊.学Python干什么用呢?我这本身是做嵌入式的, ...

  10. AARCH64 开发系列1: AARCH64 环境搭建

    首发极术社区 作者:Zhiyuan zhu 如对Arm相关技术感兴趣,欢迎私信aijishu20加入技术微信群. 概述 近年来 Arm 服务器的发展势头很猛,但大部分人的个人电脑还是 x86 环境,开 ...

最新文章

  1. Java 实例化的理解
  2. Java脚本学习-笔记二
  3. PHP CURL 哈哈哈哈哈记录一下
  4. OpenCASCADE可视化:应用交互服务之交互式上下文
  5. android 常用短语的添加,操作方法:使用Android上的百度输入法提供的导入词库和个性化短语,批量创建单词便于输入...
  6. 火车票售票系统mysql_2021年元旦火车票今日开售!具体开售时间是几点?
  7. 批量替换_【脚本】AE照片墙模板图片批量替换脚本Multi Replacer
  8. java编译遇到的问题与解决_java web开发中遇到的问题及解决方案(个人学习日志,持续更新)...
  9. QTP Flex测试
  10. 占内存最小的浏览器:360安全浏览器超速版推荐
  11. 吴晓波:预见2021(跨年演讲 —— 02 “云上中国”初露峥嵘)
  12. 张孝祥张老师一路走好!
  13. BIOS设置|win10最快启动的方式
  14. 原创 | DDD领域驱动设计第一话
  15. 计算机视觉--CV技术指南文章汇总
  16. 个人博客系统---基本功能的实现
  17. 入耳式监控系统的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  18. 北京华为HCIE认证里的数通深入学习QOS流量整形令牌桶机制和规则-ielab网络实验室
  19. ueditor的微软雅黑字体的样式错误
  20. Java+SSM求职招聘系统兼职应聘(含源码+论文+答辩PPT等)

热门文章

  1. idea连接数据库,及增删改查
  2. 爬虫基础:爬取百度贴吧-猫吧标题,详情页url,详情页图片url,下载图片
  3. 阿里出品的这个项目厉害了,专抓 App 里的 Bug
  4. 对指定日期计算出N天后的日期问题
  5. python scatter参数详解_Python中scatter函数参数用法详解
  6. ArcPy高级开发教程—属性表字段操作
  7. BNF 范式(巴科斯范式)简介
  8. CSS实现炫彩渐变滚动文字颜色
  9. 推荐研究互联网必读的10本书
  10. 安卓多媒体API——Vitamio框架