Remove the renderer from this sample, add a "create" command

This commit is contained in:
Rob Lourens
2023-01-10 16:13:30 -08:00
parent 739e41ab50
commit d7b731e7b0
17 changed files with 82 additions and 3835 deletions

View File

@ -1,9 +0,0 @@
# Change Log
All notable changes to the "notebook-serializer-example" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
## [Unreleased]
- Initial release

View File

@ -1,28 +1,15 @@
# notebook-serializer-example
# notebook-serializer-sample
⚠️ Work-in-progress starter code for custom notebook renderers in VS Code. Expect this to change as notebooks matures. ⚠️
This is a very simple extension sample demonstrating the use of the notebook serializer and controller APIs. This sample includes:
This starter includes:
- A notebook serializer that is activated for files matching `*.sample-json-notebook`. It serializes notebook data into a simple JSON-based format.
- A notebook controller that "executes" JSON-type code cells by adding an output to the cell that includes the content of the cell parsed as JSON.
- A command "Create JSON Notebook" that creates a new untitled notebook of this type.
- 🖥️ TypeScript code to create a simple `NotebookOutputRenderer`
- 📦 A Webpack build for renderer client code
- ⚡ Support for hot module reloading and safe boilerplate
- 🎨 CSS modules support
## Running this sample
### Running this Sample
1. `cd notebook-serializer-example`
1. `code-insiders .`: Open the folder in VS Code Insiders
1. `cd notebook-serializer-sample`
1. `code .`: Open the folder in VS Code
1. Hit `F5` to build+debug
### Structure
A Notebook Renderer consists of code that runs in the VS Code Extension Host (Node.js), which registers the renderer and passes data into the UI code running inside a WebView (Browser/DOM).
This uses TypeScript project references. There are three projects in the `src` directory:
- `extension` contains the code running in Node.js extension host. It's compiled with `tsc`.
- `client` is the UI code, built by Webpack, with access to the DOM.
- `common` contains code shared between the extension and client.
When you run `watch`, `compile`, or `dev`, we invoke both `tsc` and `webpack` to compile the extension and the client portion of the code.
1. Run the command "Create JSON Notebook"
1. Add and edit cells, and click the run button to invoke the controller

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,8 @@
{
"name": "notebook-serializer-example",
"displayName": "notebook-serializer-example",
"description": "Notebook using Serializer API example",
"name": "notebook-serializer-sample",
"displayName": "notebook-serializer-sample",
"description": "Notebook using Serializer API sample",
"publisher": "vscode-samples",
"version": "0.0.1",
"engines": {
"vscode": "^1.74.0"
@ -10,23 +11,20 @@
"Other"
],
"activationEvents": [
"onNotebook:test-notebook-renderer"
"onNotebook:test-notebook-serializer",
"onCommand:notebook-serializer-sample.createJsonNotebook"
],
"main": "./out/extension/extension.js",
"main": "./out/extension.js",
"contributes": {
"notebookRenderer": [
{
"id": "notebook-serializer-example",
"entrypoint": "./out/client/index.js",
"displayName": "notebook-serializer-example",
"mimeTypes": [
"x-application/sample-json-renderer"
]
}
],
"commands": [
{
"command": "notebook-serializer-sample.createJsonNotebook",
"title": "Create JSON Notebook"
}
],
"notebooks": [
{
"type": "test-notebook-renderer",
"type": "test-notebook-serializer",
"displayName": "Sample Notebook",
"selector": [
{
@ -37,35 +35,19 @@
]
},
"scripts": {
"vscode:prepublish": "npm run compile && node out/test/checkNoTestProvider.js",
"compile": "npm run compile:extension && npm run compile:client",
"compile:extension": "tsc -b",
"compile:client": "webpack --mode production",
"vscode:prepublish": "npm run compile",
"compile": "tsc -b",
"lint": "eslint src --ext ts",
"watch": "concurrently -r \"npm:watch:*\"",
"watch:extension": "tsc -b --watch",
"watch:client": "webpack --mode development --watch"
"watch": "tsc -b --watch"
},
"devDependencies": {
"@types/glob": "^7.1.3",
"@types/mocha": "^8.2.2",
"@types/node": "14.x",
"@types/vscode": "^1.74.0",
"@types/vscode-notebook-renderer": "^1.72.0",
"@types/webpack-env": "^1.16.0",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"concurrently": "^5.3.0",
"css-loader": "^4.2.0",
"eslint": "^7.27.0",
"fork-ts-checker-webpack-plugin": "^5.0.14",
"glob": "^7.1.7",
"mocha": "^10.2.0",
"style-loader": "^1.2.1",
"ts-loader": "^9.2.2",
"typescript": "^4.3.2",
"vscode-notebook-error-overlay": "^1.0.1",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.0"
"typescript": "^4.3.2"
}
}

View File

@ -1,4 +0,0 @@
declare module '*.css' {
const classes: { [className: string]: string };
export = classes;
}

View File

@ -1,42 +0,0 @@
import { render } from './render';
import errorOverlay from 'vscode-notebook-error-overlay';
import type { ActivationFunction } from 'vscode-notebook-renderer';
// Fix the public path so that any async import()'s work as expected.
declare const __webpack_relative_entrypoint_to_root__: string;
declare const scriptUrl: string;
__webpack_public_path__ = new URL(scriptUrl.replace(/[^/]+$/, '') + __webpack_relative_entrypoint_to_root__).toString();
// ----------------------------------------------------------------------------
// This is the entrypoint to the notebook renderer's webview client-side code.
// This contains some boilerplate that calls the `render()` function when new
// output is available. You probably don't need to change this code; put your
// rendering logic inside of the `render()` function.
// ----------------------------------------------------------------------------
export const activate: ActivationFunction = context => {
return {
renderOutputItem(outputItem, element) {
let shadow = element.shadowRoot;
if (!shadow) {
shadow = element.attachShadow({ mode: 'open' });
const root = document.createElement('div');
root.id = 'root';
shadow.append(root);
}
const root = shadow.querySelector<HTMLElement>('#root')!;
errorOverlay.wrap(root, () => {
root.innerHTML = '';
const node = document.createElement('div');
root.appendChild(node);
render({ container: node, mime: outputItem.mime, value: outputItem.json(), context });
});
},
disposeOutputItem(outputId) {
// Do any teardown here. outputId is the cell output being deleted, or
// undefined if we're clearing all outputs.
}
};
};

View File

@ -1,32 +0,0 @@
// We've set up this sample using CSS modules, which lets you import class
// names into JavaScript: https://github.com/css-modules/css-modules
// You can configure or change this in the webpack.config.js file.
import * as style from './style.css';
import type { RendererContext } from 'vscode-notebook-renderer';
interface IRenderInfo {
container: HTMLElement;
mime: string;
value: any;
context: RendererContext<unknown>;
}
// This function is called to render your contents.
export function render({ container, mime, value }: IRenderInfo) {
// Format the JSON and insert it as <pre><code>{ ... }</code></pre>
// Replace this with your custom code!
const pre = document.createElement('pre');
pre.classList.add(style.json);
const code = document.createElement('code');
code.className = 'output';
code.textContent = `mime type: ${mime}\n\n${JSON.stringify(value, null, 2)}`;
pre.appendChild(code);
container.appendChild(pre);
}
if (module.hot) {
module.hot.addDisposeHandler(() => {
// In development, this will be called before the renderer is reloaded. You
// can use this to clean up or stash any state.
});
}

View File

@ -1,8 +0,0 @@
.json code {
font-family: monospace;
font-size: 12px;
}
.output {
background-color: lightblue;
}

View File

@ -1,11 +0,0 @@
{
"extends": "../tsconfig-base.json",
"compilerOptions": {
// noEmit prevents the default tsc from building this--we use webpack instead
"noEmit": true,
"rootDir": ".",
"module": "esnext",
"lib": ["ES2019", "dom"],
"types": ["webpack-env", "vscode-notebook-renderer"],
}
}

View File

@ -1,7 +1,7 @@
import * as vscode from 'vscode';
export class SampleKernel {
private readonly _id = 'test-notebook-renderer-kernel';
private readonly _id = 'test-notebook-serializer-kernel';
private readonly _label = 'Sample Notebook Kernel';
private readonly _supportedLanguages = ['json'];
@ -11,7 +11,7 @@ export class SampleKernel {
constructor() {
this._controller = vscode.notebooks.createNotebookController(this._id,
'test-notebook-renderer',
'test-notebook-serializer',
this._label);
this._controller.supportedLanguages = this._supportedLanguages;
@ -37,7 +37,6 @@ export class SampleKernel {
try {
execution.replaceOutput([new vscode.NotebookCellOutput([
vscode.NotebookCellOutputItem.json(JSON.parse(cell.document.getText()), "x-application/sample-json-renderer"),
vscode.NotebookCellOutputItem.json(JSON.parse(cell.document.getText()))
])]);

View File

@ -0,0 +1,33 @@
import * as vscode from 'vscode';
import { SampleKernel } from './controller';
import { SampleContentSerializer } from './serializer';
const NOTEBOOK_TYPE = 'test-notebook-serializer';
export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.commands.registerCommand('notebook-serializer-sample.createJsonNotebook', async () => {
const language = 'json';
const defaultValue = `{ "hello_world": 123 }`;
const cell = new vscode.NotebookCellData(vscode.NotebookCellKind.Code, defaultValue, language);
const data = new vscode.NotebookData([cell]);
data.metadata = {
custom: {
cells: [],
metadata: {
orig_nbformat: 4
},
nbformat: 4,
nbformat_minor: 2
}
};
const doc = await vscode.workspace.openNotebookDocument(NOTEBOOK_TYPE, data);
await vscode.window.showNotebookDocument(doc);
}));
context.subscriptions.push(
vscode.workspace.registerNotebookSerializer(
NOTEBOOK_TYPE, new SampleContentSerializer(), { transientOutputs: true }
),
new SampleKernel()
);
}

View File

@ -1,15 +0,0 @@
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import { SampleKernel } from './controller';
import { SampleContentSerializer } from './provider';
export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(
vscode.workspace.registerNotebookSerializer(
'test-notebook-renderer', new SampleContentSerializer(), { transientOutputs: true }
),
new SampleKernel()
);
}

View File

@ -1,8 +0,0 @@
{
"extends": "../tsconfig-base.json",
"compilerOptions": {
"rootDir": ".",
"outDir": "../../out/extension",
},
"references": []
}

View File

@ -1,17 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "ES2019",
"lib": [
"ES2019"
],
"types": ["node"],
"moduleResolution": "node",
"sourceMap": true,
"strict": true /* enable all strict type-checking options */
/* Additional Checks */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
}
}

View File

@ -1,11 +1,17 @@
{
"files": [],
"references": [
{
"path": "./src/client"
},
{
"path": "./src/extension"
}
]
}
"compilerOptions": {
"module": "commonjs",
"target": "es2020",
"lib": [
"es2020"
],
"outDir": "out",
"sourceMap": true,
"strict": true,
"rootDir": "src"
},
"exclude": [
"node_modules",
".vscode-test"
]
}

View File

@ -1,79 +0,0 @@
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const { DefinePlugin } = require('webpack');
const path = require('path');
const outputFilename = 'index.js';
const devServerPort = 8111;
module.exports = (env, argv) => ({
mode: argv.mode,
devtool: argv.mode === 'production' ? false : 'inline-source-map',
entry: './src/client/index.ts',
output: {
path: path.join(__dirname, 'out', 'client'),
filename: outputFilename,
publicPath: '',
libraryTarget: 'module',
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.css'],
},
experiments: {
outputModule: true,
},
module: {
rules: [
// Allow importing ts(x) files:
{
test: /\.tsx?$/,
loader: 'ts-loader',
options: {
configFile: 'src/client/tsconfig.json',
// transpileOnly enables hot-module-replacement
transpileOnly: true,
compilerOptions: {
// Overwrite the noEmit from the client's tsconfig
noEmit: false,
},
},
},
// Allow importing CSS modules:
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: true,
},
},
],
},
],
},
devServer: {
port: devServerPort,
hot: true,
// Disable the host check, otherwise the bundle running in VS Code won't be
// able to connect to the dev server
disableHostCheck: true,
writeToDisk: true,
headers: { 'Access-Control-Allow-Origin': '*' },
},
plugins: [
new ForkTsCheckerWebpackPlugin({
typescript: {
tsconfig: 'src/client/tsconfig.json',
},
}),
new DefinePlugin({
// Path from the output filename to the output directory
__webpack_relative_entrypoint_to_root__: JSON.stringify(
path.posix.relative(path.posix.dirname(`/${outputFilename}`), '/'),
),
scriptUrl: 'import.meta.url',
}),
],
});