ue作为三大主流前端开发框架之一,近年来用户群发展迅速,用其开发的软件项目越来越多。
vue开发环境(development)和生产环境(production)的构建目标差异很大。
开发环境中,我们需要具有强大的,具有实时重新加载(live reloading)或热模块替换(hot module replacement)能力的 source map 和 localhost server。
生产环境中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间。
遵循逻辑分离原则,通常为每个环境编写彼此独立的 webpack 配置。同时遵循不重复原则(Don't repeat yourself - DRY),保留一个"通用"配置。将这些配置合并在一起,需用webpack-merge。
根据不同的"标识" 加载应用时,自动更换主题
vue-cli 全家桶,主要(vuex,vue-router),less ,webpack,多套同样目录结构的主题静态资源(css,img图片)
1、把所需要改变主题的vue组件中的style全部提出来,按照目录结构提取到static目录中,用less内联写法防止样式冲突。
2、利用require去动态的给每个需要的组件渲染css和img
以上开发环境就ok了。
1、vue-cli脚手架build目录中的webpack.prod.conf.js配置文件是webpack生产环境的核心配置文件。
2、webpack run build以后会把多个主题的css打包成一个大的css,会造成样式冲突
解决办法是在webpack的生产配置文件webpack.prod.conf.js中,修改一下设置,把extract的true改成false即可,会发现那个css文件从几百k,变成几十k,样式就不会冲突了。
extract: true,此项是自定义项,设置为true表示,生成独立的文件
好!欢迎了解我们常用的网站建设工具——帝国CMS,其中的采集功能可实现自动获取他站文章并同步至您站点。尽管如此,因每个网站的版面构造与形式各异,可能导致采集内容在展示时产生形变。接下来我们简述为何文章会变形以及如何避免这一情况。
1.采集规则设置不当
在用帝国CMS进行采集时,正确设定采集中的规则至关重要,因为这关系到能否精准地获取目标网站内容。若规则有误,可能会带来文章乱码、排版失衡等问题。因此,我们建议您妥善调整采集规则,以避免文章变形。
2.编码问题
由于不同网站采用的编码各异,若未妥善处理编码问题,便易致使乱码或显示异常。故采集中,务必先确认网站编码,再据此设定采集规则。
3. CSS样式冲突
我们的帝国CMS在文章采集过程中,虽然会尊重原始网站的CSS样式,但是这可能会引起样式之间的冲突,从而影响到文章的正常排版显示。因此,建议您在发布前,通过调整采集规则上的CSS特效,或在内容编辑完成之后,手动微调一下样式,以确保排版效果的完美呈现。
4.图片链接失效
在您原创的文章里常会包含一些图片,但有时因为它们指向的是相对于当前文档路径或来自其他网站的图片已失效,所以可能会让帝国CMS无法正常展示这些内容。为了解决这个问题,我们建议您将图片的链接更改为绝对路径,或者重新将图片上传至自己的服务器以确保其有效链接。
5.链接转换错误
部分网站文章内的链接,有时会因为采集规则设定或目标站点故障等原因,出现未能正常转换的情况。建议您仔细查看采集规则的链接转换设定是否合理,如有必要可作相应调整。
6.特殊字符处理不当
对于在帝国CMS系统中无法正常呈现的特殊字符(如特殊符号、表情符号等),可能会使您的文章出现排版问题。此时,建议您尝试在采集规则设置中对其进行适当处理;若无法实现,也可以直接对文章内容做手动修正。
7.文章结构错乱
某些网站的文章结构较为繁杂,引入了许多标题、段落及列表等元素。如此一来,在使用帝国CMS录入时,文章的结构层次便有可能被混淆,使得文章排版显得凌乱。为了避免这类问题,我们建议您在设定采集中,针对文章结构进行调整,或者通过手动编辑完成排版。
8.人工校对和修复
虽然帝国CMS具备强大的采集能力,但是依然有可能因为种种因素导致部分采集来的文章存在变形现象。此时,人工校对与修复便成为了我们坚守的最后防线。我们会细心地进行文章内容审核及修正工作,以全力保证展示给大家的文章品质符合标准哦!
在使用帝国cms进行文章采集中,常常遇到文章变形的情况。为改善这种状况,请合理解定采集规则,处理好编码出错的部分,运用CSS功能微调文章样式,修复图片无法显示的问题,检查链接是否转换正确,巧妙处理特殊字符,以及调整文章结构。此外,别忘了人工校对并进行必要的修正以提升文章质量与可阅读性。希望这篇简明易懂的指南能助您一臂之力!
微前端已经成为前端领域如今比较火爆的话题,关于微前端价值的讨论,可以参考克军的《拥抱云时代的前端开发框架——微前端》。微前端在技术方面,有一个始终绕不过去话题就是前端沙箱。本篇具体探讨一下,在微前端领域如何实现前端沙箱。
应用沙箱可能是微前端技术体系里面最有意思的部分。一般来说沙箱是微前端技术体系中不是必须要做的事情,因为如果规范做的足够好,是能够避免掉一些变量冲突读写,CSS 样式冲突的情况。但是如果你在一个足够大的体系中,总不能仅仅通过规范来保证应用的可靠性,还是需要技术手段去治理运行时的一些冲突问题,这个也是沙箱方案成为微前端技术体系的一部分原因。
首先纵观各类技术方案,有一个大前提决定了这个沙箱如何做:最终微应用是 单实例 or 多实例 存在宿主应用中。这个直接决定了这个沙箱的复杂度和技术方案。
• 单实例:同一个时刻只有一个微应用实例存在,此刻浏览器所有浏览器资源都是这个应用独占的,方案要解决的很大程度是应用切换的时候的清理和现场恢复。比较轻量,实现起来也简单。
• 多实例:资源不是应用独占,就要解决资源共享的情况,比如路由,样式,全局变量读写,DOM. 可能需要考虑的情况比较多,实现较为复杂。
最开始我们的想法是:
从业务场景:我们可能存在的情况是当用户操作一个产品 A 的同时和另一个产品 B 发生了关联操作,需要唤醒应用 B 做操作。虽然从产品维度可以规避掉,比如先切到 B, 然后切回 A, 但是从某种程度上因为技术的原因,我们限制了产品交互的发挥。
从技术角度:解决了多实例当然单实例的场景也不在话下,并且单实例的方案某种程度上给编码上带来了一定复杂度,比如业务代码需要自己做业务上下文的切换。
最近 qiankun 2 也转变了思路从单实例的支持到开始支持多实例,多多少少也侧面说明了,多实例是一个值得投入和技术攻克的场景。
基于上面的考量,我们就开始了我们 Browser VM 沙箱的实现探索。总结起来可以用下图表示:
沙箱环境构造要实现沙箱,我们需要隔离掉浏览器的原生对象,但是如何隔离,建立一个沙箱环境呢?Node 中 有 vm 模块,来实现类似的能力,但是浏览器就不行了,但是我们可以利用了闭包的能力,利用变量作用域去模拟一个沙箱环境,比如下面的代码:
function foo(window) {
console.log(window.document);
}
foo({
document: {};
});
比如这段代码的输出一定是 {}. 而不是原生浏览器的 document.
所以 ConsoleOS 实现了一个 wepback 的插件在应用代码构建的时候给子应用代码加上一层 wrap 代码,创建一个闭包,把需要隔离的浏览器原生对象变成从下面函数闭包中获取的,从而我们可以在应用加载的时候,传入模拟掉的 window,document 之类的对象。
// 打包代码
__CONSOLE_OS_GLOBAL_HOOK__(id, function (require, module, exports, {window, document, location, history}) {
/* 打包代码 */
})
function __CONSOLE_OS_GLOBAL_HOOK__(id, entry) {
entry(require, module, exports, {window, document, location, history})
}
当然也可以不靠工程化的手段来实现,也可以通过请求脚本,然后在运行时拼接这段代码,然后eval 或者 new Function, 来达到相同的目的。
原生对象模拟沙箱隔离能力有了,剩下的问题就是如何实现这一堆浏览器的原生对象了。最开始的想法是我们根据 ECMA 的规范实现(现在仍然有类似的想法),但是发现成本太高。不过在我们各种实验之后,发现了一个很“取巧”的做法,我们可以 new iframe 对象,把里面的原生浏览器对象通过 contentWindow 取出来,应为这些对象天然隔离,就省去了自己实现的成本。
const iframe = document.createElement( 'iframe' );
当然里面有很多的细节需要考量,比如:
只有同域的 iframe 才能取出对应的的 contentWindow. 所以需要提供一个宿主应用空的同域URL来作为这个 iframe 初始加载的 URL. 当然根据 HTML 的规范 这个 URL 用了 about:blank 一定保证保证同域,也不会发生资源加载,但是会发生关联的 和 这个iframe 中关联的 history 不能被操作,这个时候路由的变换只能变成 hash 模式。
如下图所示,我们取出对应的 iframe 中原生的对象之后,就会对特定需要隔离的对象生成对应的 Proxy, 然后对一些属性获取和属性设置,做上一些特定的设置,比如 window.document 需要返回特定的沙箱 document 而不是当前浏览器的document.
class Window {
constructor(options, context, frame) {
return new Proxy(frame.contentWindow, {
set(target, name, value) {
target[name] = value;
return true;
},
get(target, name) {
switch( name ) {
case 'document':
return context.document;
default:
}
if( typeof target[ name ] === 'function' && /^[a-z]/.test( name ) ){
return target[ name ].bind && target[ name ].bind( target );
}else{
return target[ name ];
}
}
});
}
}
对于每一个对象的实现这里不讲细节了,有兴趣可以看看我们的开源之后的代码,点击前往>>>
但是为了文档能够被加载在同一个 DOM 树上,对于 document, 大部分的 DOM 操作的属性和方法还是直接用的宿主浏览器中的 document 的属性和方法。
由于子应用有自己的沙箱环境,之前所有独占式的资源现在都变成了应用独享(尤其是 location, history),所以子应用也能同时被加载. 并且对于一些变量的我们还能在 proxy 中设置一些访问权限的事情,从而限制子应用的能力,比如 Cookie, LocalStoage 读写。
当这个 iframe 被移除时,写在 window 的变量和设置的一些 timeout 时间也会一并被移除。(当然 DOM 事件需要沙箱记录,然后在宿主中移除)。
总结一下,我们的沙箱可以做到如下的特性:
CSS 隔离方案相对来说比较常规,常见的有:• CSS Module• 添加 css 的 namespace• Dynamic StyleSheet• Shadow DOM
CSS Module or CSS Namespace: 通过修改基础组件样式前缀来实现框架和微应用依赖基础组件样式的隔离性(依赖于工程上 CSS 的预处理器编译和运行时基础组件库配置),同时避免全局样式的书写(依赖于约定或工程 lint 手段)。
Dynamic StyleSheet: 隔离方式是通过js运行时动态加载卸载微应用样式表来避免样式的冲突,局限性一是在于站点框架本身或其部件(header/menu/footer)与当前运行的微应用间仍存在样式冲突的可能性,二是没有办法支持多个微应用同时运行显示的情况。
Shadow DOM: 优点是浏览器级别提供的样式隔离能力,可以做到完全隔离。缺点在于,目前兼容性还是够不太好,并且改造会涉及到旧应用的业务代码的改造,对子应用侵入性比较高。
最终经过实践,我们选择的方式是 CSS Module + 添加 CSS 的 namespace。CSS module 保证的是应用业务样式不冲突,Namespace 保证公共库不冲突。我们实现了一个 postcss 插件,会在应用构建的时候给所有的样式都加上应用前缀包括应用公共库的 CSS。(这样方便做到同一个 组件库 新旧版本样式的兼容)。如下图所示:
// 宿主 host app
.next-btn {
color: #eee;
}
// 子应用 sub app
aliyun-slb .next-btn {
color: #eee;
}
//宿主中生成的节点
<aliyun-slb>
<!-- 子应用的节点 -->
</aliyun-slb>
这样实现的好处在于:• 每个应用都有 namespace, 可以多实例共存。• 不依赖特定的 CSS 预处理器。• 对于同一个库不同版本的 CSS(如 fusion1 和 fusion2), 可以做到彻底隔离。• 鉴于上面 JS 沙箱的存在,对于一些弹窗类的组件,这个微应用获取的 body 实际上是宿主生成的节点,所以弹窗会被添加到微应用的节点(也就是上面的 aliyun-slb)这个节点,样式不会失效。
不过也会有一些问题,比如:• 嵌套应用组件样式优先级的问题。(由于 CSS module 的存在,一般只会发生在公共 css 样式中,这个就是只能尽量避免嵌套)。• fusion 不同版本库公用字体的问题。(目前解法比较hack, 工程化手段替换掉了 next 字体的名字)。
一般来说,所以如果看完上面的文章,觉得这个沙箱方案不错,但是又有自己的微前端体系了,想套用咋办?
目前 ConsoleOS 的代码已经在 Github 上开源这里不妨可以尝试试用一下,点击前往>>>
JS 沙箱部分:如果看懂了上面关于原理的介绍可以看到其实沙箱实现包括两个层面
• 原生浏览器对象的模拟(Browser-VM)的部分• 如何构建一个闭包环境的部分。
Browser-VM 可以直接用起来,这部分完全是通用普适的。 但是涉及到闭包构建的这部分,每个微前端体系不太一致,可能需要改造比如:
import { createContext, removeContext } from '@alicloud/console-os-browser-vm';
const context = await createContext();
const run = window.eval(`
(() => function({window, history, locaiton, document}) {
window.test = 1;
})()
`)
run(context);
console.log(context.window.test);
console.log(window.test);
// 操作虚拟化浏览器对象
context.history.pushState(null, null, '/test');
context.locaiton.hash = 'foo'
// 销毁一个 context
await removeContext( context );
当然可以直接选择沙箱提供好的 evalScripts 方法:
import { evalScripts } from '@alicloud/console-os-browser-vm';
const context = evalScripts('window.test = 1;')
console.log(window.test === undefined) // true
CSS 沙箱如果用webpack 构建,可以直接配置如下:
const postcssWrap = require('@alicloud/console-toolkit-plugin-os/lib/postcssWrap')
// 下面是 webpack config
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'postcss-loader',
options: {
plugins: [
// 加入插件
postcssWrap({
stackableRoot: '.prefix',
repeat: 1
})
],
},
},
'css-loader',
],
exclude: /^node_modules$/,
}
与其干巴巴的看文章,直接试试在线 Demo 可能更有体感一些,或者试试生产环境的例子, 阿里云企业工作台 - 工具应用中心 , 是阿里云集成三方应用提供云管能力。这里每个应用都是一个微应用,里面涵盖了 React, Vue, Angular 三大技术栈。
*请认真填写需求信息,我们会在24小时内与您取得联系。