大家好,今天继续来开发元件,并动手解决实务上我们遇到的设定配置的问题。在昨天的练习里,我们可以使用babal-plugin-import按需载入使用到的第三方UI元件的css,之後使用yarn start启动react的web,并在浏览器显示正确的结果,但其实在Webview里,这样设定仍有些地方需要调整。
在之前的Webview单元我们提到,VSCode的WebView里要访问script的资源跟css时有限制,要将script跟css边谦里的url专换为webview专用的Uri才能顺利生效。
在没有使用rewired多import其他ui的library前,使用Create React App生成的的asset-manifest.json是这个样子,如下所示,js档案分为三支档案。css有一支,对应到files属性下的main.css路径。
{
"files": {
"main.css": "./static/css/main.5f361e03.chunk.css",
...
},
"entrypoints": [
"static/js/runtime-main.e139f7bb.js",
"static/js/2.390c405e.chunk.js",
"static/css/main.5f361e03.chunk.css",
"static/js/main.2ba94f4f.chunk.js"
]
}
在webview专案底下使用rewired改写过後的yarn build後,让我们到out/build/asset-manifest.json底下查看,可以发现在多打包一个UI Library的css後,entrypoints下面的css档案变为两支,且有一支我们无法直接在files下面透过随机产生的static/css的key值获取正确路径的css分块档案。
{
"files": {
"main.css": "./static/css/main.dc44bd41.chunk.css",
...
"static/css/2.438752f9.chunk.css": "./static/css/2.438752f9.chunk.css",
...
},
"entrypoints": [
"static/js/runtime-main.2206c2b6.js",
"static/css/2.438752f9.chunk.css",
"static/js/2.f197f274.chunk.js",
"static/css/main.dc44bd41.chunk.css",
"static/js/main.b3ed2647.chunk.js"
]
}
因此,当我们在WebviewPanel里使用前面的loadWebViewContent方法时,我们读取css档案的底下这段
<link rel="stylesheet" type="text/css" href="${this.webviewUri(mainfest.files['main.css'])}">
路径会失效。
这边笔者处理被webpack分块後的css档案做法和前面处理分块後的js档案做法一样。在我们的loadWebcontent方法里,我们直接透过字串filter出我们的所有分块过的css档案。
const entrypointsCss = mainfest['entrypoints'].filter((p: string) => p.includes('static/css'));
之後,在样板字串里我们直接透过阵列index取得所有css的档案路径,并使用先前我们准备好的webviewUri转换方法转换css路径,即可让WebView正确的读取所有我们所需的css档案。
<link rel="stylesheet" type="text/css" href="${this.webviewUri(entrypointsCss[0])}">
<link rel="stylesheet" type="text/css" href="${this.webviewUri(entrypointsCss[1])}">
loadWebviewContent完整的精简版方法如下所示:
class WebviewPanel {
...
public loadWebviewContent() {
const mainfest = readJSON(path.join(this.context.extensionPath, 'out/build/asset-manifest.json'));
const entrypointsJs = mainfest['entrypoints'].filter((p: string) => p.includes('static/js'));
const entrypointsCss = mainfest['entrypoints'].filter((p: string) => p.includes('static/css'));
return `<!DOCTYPE html>
<html lang="en">
<head>
<link rel="icon" href="${this.webviewUri('./favicon.ico')}"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="theme-color" content="#000000"/>
<meta name="description" content="Web site created using create-react-app"/>
<title>React App</title>
<base href="${this.webviewUri('/')}">
<link rel="stylesheet" type="text/css" href="${this.webviewUri(mainfest.files['main.css'])}">
<link rel="stylesheet" type="text/css" href="${this.webviewUri(entrypointsCss[0])}">
<link rel="stylesheet" type="text/css" href="${this.webviewUri(entrypointsCss[1])}">
<link rel="manifest" href="${this.webviewUri('./manifest.json')}"/>
</head>
<body
<div id="root"></div>
<script src="${this.webviewUri(entrypointsJs[0])}"></script>
<script src="${this.webviewUri(entrypointsJs[1])}"></script>
<script src="${this.webviewUri(entrypointsJs[2])}"></script>
</body>
</html>`;
}
}
现在我们调整完了loadWebviewContent方法,再启动extension,即会正确的在VSCode里面显示react使用第三方元件後的css的样式。
在笔者上面的做法里,需在build完後的asset-manifest.json里检查有几只切分出去的档案,并手动套用到loadWebviewContent的html里。但其实我们也可以使用另一种方式解决问题,在Open Source的世界里,有一个vscode-webview-react的react vscode webview template专案,里面使用了直接禁用webpack的split chunk设定的方式来解决问题。
在vscode-webview-react专案里,有一支build-non-split.js档,引入了rewired这个套件停用webpack的相关split chunk属性。
#!/usr/bin/env node
// Disables code splitting into chunks
// See https://github.com/facebook/create-react-app/issues/5306#issuecomment-433425838
const rewire = require("rewire");
const defaults = rewire("react-scripts/scripts/build.js");
let config = defaults.__get__("config");
config.optimization.splitChunks = {
cacheGroups: {
default: false
}
};
config.optimization.runtimeChunk = false;
这里我们可以参考相关的Wepack设定做配置。
在我们的专案里,我们会在config-overrides.js下面使用不同套件做配置。
这里笔者参考套件写法的风格撰写一个客制化的buildNonSplit方法进行webpack的设定,全部配置如下。
const {
override,
fixBabelImports
} = require('customize-cra');
const buildNonSplit = () => config => {
config.optimization.splitChunks = {
cacheGroups: {
default: false
}
};
config.optimization.runtimeChunk = false;
return config;
};
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd-mobile',
style: 'true',
}),
buildNonSplit()
);
2020/11/03更正: 阅读套件程序後了解,customize-cra套件实际上有针对同一个issue提供禁用code split的工具方法,详见Github连结,我们可以直接使用内建的disableChunk方法。
const { override, disableChunk, fixBabelImports } = require('customize-cra'); module.exports = override( fixBabelImports('import', { libraryName: 'antd-mobile', style: 'true', }), disableChunk() );
好的,现在我们使用yarn build,再到out/build/asset-manifest.json档案下面查看结果,可以确认entrypoints下面仅有main.js与main.css两只档案
```json=
{
"files": {
"main.css": "./static/css/main.e7c5d175.css",
"main.js": "./static/js/main.1d4ca48f.js",
"main.js.map": "./static/js/main.1d4ca48f.js.map",
"index.html": "./index.html",
"static/css/main.e7c5d175.css.map": "./static/css/main.e7c5d175.css.map",
"static/js/main.1d4ca48f.js.LICENSE.txt": "./static/js/main.1d4ca48f.js.LICENSE.txt"
},
"entrypoints": [
"static/css/main.e7c5d175.css",
"static/js/main.1d4ca48f.js"
]
}
现在在我们的loadWebviewContent方法里,我们仅需简单的引用files属性下的main.js与main.css路径即可让Webview使用。
// 引入main.css
<link rel="stylesheet" type="text/css" href="${this.webviewUri(mainfest.files['main.css'])}">
...
// 引入main.js
<script src="${this.webviewUri(mainfest.files['main.js'])}"></script>
好的,今天我们花了些时间处理跟Create React App里的Webpack设定,并将其套用到webview上。会让人感到有些繁琐,但这是实务开发上必然会遇到的过程。
在今天笔者也示范了两种解决问题的方式,选用哪种方式处理引入的css或js档案路径,视乎专案是否需要Webpack的分块与相关优化设定。Open Source世界里的专案解法是我们很好的参考资源,但未必就会是当下最适合我们情境的解法。在我们理解背後相关原理後,我们可以为专案找到符合各自情境的解决方法,视情况采取不同方式。
>>: [鼠年全马] W35 - Vue出一个旅馆预约平台(9)
昨天介绍了 AsyncPipe 的用法以及它可以带来的便利,今天要来看一下在这方便的背後是由那些东西...
连续 30 天不中断每天上传一支教学影片,教你如何用 React 加上 Firebase 打造社群...
想要更便捷的来开启云端服务吗?CloudFormation帮我们搞定! 1. CloudFormat...
延续前一天的程序码,首先先把图片里的程序码搬到箭头的地方,固定前面放函数後面放程序,这样看起来比较清...
2020/10/29 在几年前我就一直实践Mobile first, Cloud first这两大准...