├── CONTRIBUTING.md
├── .gitignore
├── images
├── icon.png
└── feature.gif
├── test
├── test.js
├── extension.test.ts
├── test.html
└── index.ts
├── .vscodeignore
├── .vscode
├── settings.json
├── tasks.json
└── launch.json
├── tsconfig.json
├── i18n
└── jpn
│ └── package.i18n.json
├── package.nls.ja.json
├── LICENSE
├── package.nls.json
├── src
├── browserContentProvider.ts
├── server.ts
├── utility.ts
└── extension.ts
├── CHANGELOG.md
├── gulpfile.js
├── tslint.json
├── README.md
└── package.json
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ### Contributions are welcome 😸
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 | node_modules
3 | npm-debug.log
4 | vsc-extension-quickstart.md
5 |
--------------------------------------------------------------------------------
/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YuichiNukiyama/vscode-preview-server/HEAD/images/icon.png
--------------------------------------------------------------------------------
/images/feature.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YuichiNukiyama/vscode-preview-server/HEAD/images/feature.gif
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | const app = new Vue({
2 | el: "#target",
3 | data: {
4 | message: "I love cat!"
5 | }
6 | });
--------------------------------------------------------------------------------
/.vscodeignore:
--------------------------------------------------------------------------------
1 | .vscode/**
2 | .vscode-test/**
3 | out/test/**
4 | test/**
5 | src/**
6 | **/*.map
7 | .gitignore
8 | tsconfig.json
9 | tslint.json
10 | vsc-extension-quickstart.md
11 |
--------------------------------------------------------------------------------
/test/extension.test.ts:
--------------------------------------------------------------------------------
1 | import * as assert from "assert";
2 | import * as browserSync from "browser-sync";
3 | import { Server } from "../src/server";
4 |
5 |
6 | suite("Server Tests", () => {
7 | test("start server", () => {
8 | Server.start(".", 8888, true);
9 | assert.ok(browserSync.has("vscode-preview-server"));
10 | Server.stop();
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "files.exclude": {
4 | "out": false // set this to true to hide the "out" folder with the compiled JS files
5 | },
6 | "search.exclude": {
7 | "out": true // set this to false to include "out" folder in search results
8 | },
9 | "typescript.tsdk": "./node_modules/typescript/lib" // we want to use the TS server from our node_modules folder to control its version
10 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | // See https://go.microsoft.com/fwlink/?LinkId=733558
2 | // for the documentation about the tasks.json format
3 | {
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "type": "npm",
8 | "script": "watch",
9 | "problemMatcher": "$tsc-watch",
10 | "isBackground": true,
11 | "presentation": {
12 | "reveal": "never"
13 | },
14 | "group": {
15 | "kind": "build",
16 | "isDefault": true
17 | }
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "outDir": "out",
6 | "lib": [
7 | "es6"
8 | ],
9 | "sourceMap": true,
10 | "allowJs": true,
11 | "rootDir": ".",
12 | "noImplicitAny": true,
13 | "noImplicitReturns": true,
14 | "noImplicitThis": true,
15 | "noUnusedLocals": true,
16 | "noUnusedParameters": true
17 | },
18 | "include": [
19 | "src/**/*",
20 | "test/**/*",
21 | "typings/**/*"
22 | ],
23 | "exclude": [
24 | "node_modules",
25 | ".vscode-test",
26 | ".vscode"
27 | ]
28 | }
--------------------------------------------------------------------------------
/test/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Test page
8 |
19 |
20 |
21 |
22 |
test
23 |

24 |
{{message}}
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/i18n/jpn/package.i18n.json:
--------------------------------------------------------------------------------
1 | {
2 | "extension.preview.title": "vscode-preview-server: サイドパネルでプレビュー表示",
3 | "extension.launch.title": "vscode-preview-server: ブラウザーで起動",
4 | "extension.stop.title": "vscode-preview-server: Web サーバーを停止",
5 | "extension.resume.title": "vscode-preview-server: Web サーバーを再起動",
6 | "extension.ui.title": "vscode-preview-server: UI ページを表示",
7 | "previewServer.browsers.description": "プレビュー表示するブラウザー。",
8 | "previewServer.ignoreDefaultBrowser.description": "既定のブラウザーを起動しない。",
9 | "previewServer.isWatchConfiguration.description": "設定を変更したとき、Web サーバーを再起動するかどうか。",
10 | "previewServer.port.description": "Web サーバーのポート番号",
11 | "previewServer.proxy.description": "プロキシ URL で仮想ホストをラップして、サイトを表示します。",
12 | "previewServer.startupProject.description": "起動プロジェクト名。この設定は、ワークスペースを使用している場合のみ意味があります。",
13 | "previewServer.sync.description": "非同期かどうか。",
14 | "previewServer.ui.description": "UI ページの設定"
15 | }
--------------------------------------------------------------------------------
/package.nls.ja.json:
--------------------------------------------------------------------------------
1 | {
2 | "extension.preview.title": "vscode-preview-server: サイドパネルでプレビュー表示",
3 | "extension.launch.title": "vscode-preview-server: ブラウザーで起動",
4 | "extension.stop.title": "vscode-preview-server: Web サーバーを停止",
5 | "extension.resume.title": "vscode-preview-server: Web サーバーを再起動",
6 | "extension.ui.title": "vscode-preview-server: UI ページを表示",
7 | "previewServer.browsers.description": "プレビュー表示するブラウザー。",
8 | "previewServer.ignoreDefaultBrowser.description": "既定のブラウザーを起動しない。",
9 | "previewServer.ignoreNotification.description": "通知を表示するかどうか。",
10 | "previewServer.isWatchConfiguration.description": "設定を変更したとき、Web サーバーを再起動するかどうか。",
11 | "previewServer.port.description": "Web サーバーのポート番号",
12 | "previewServer.proxy.description": "プロキシ URL で仮想ホストをラップして、サイトを表示します。",
13 | "previewServer.startupProject.description": "起動プロジェクト名。この設定は、ワークスペースを使用している場合のみ意味があります。",
14 | "previewServer.sync.description": "非同期かどうか。",
15 | "previewServer.ui.description": "UI ページの設定"
16 | }
--------------------------------------------------------------------------------
/test/index.ts:
--------------------------------------------------------------------------------
1 | //
2 | // PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
3 | //
4 | // This file is providing the test runner to use when running extension tests.
5 | // By default the test runner in use is Mocha based.
6 | //
7 | // You can provide your own test runner if you want to override it by exporting
8 | // a function run(testRoot: string, clb: (error:Error) => void) that the extension
9 | // host can call to run the tests. The test runner is expected to use console.log
10 | // to report the results back to the caller. When the tests are finished, return
11 | // a possible error to the callback or null if none.
12 |
13 | const testRunner = require("vscode/lib/testrunner");
14 |
15 | // You can directly control Mocha options by uncommenting the following lines
16 | // See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
17 | testRunner.configure({
18 | ui: "tdd", // the TDD UI is being used in extension.test.ts (suite, test, etc.)
19 | useColors: true // colored output from test results
20 | });
21 |
22 | module.exports = testRunner;
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Yuichi Nukiyama
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | // A launch configuration that compiles the extension and then opens it inside a new window
2 | {
3 | "version": "0.1.0",
4 | "configurations": [
5 | {
6 | "name": "Extension",
7 | "type": "extensionHost",
8 | "request": "launch",
9 | "runtimeExecutable": "${execPath}",
10 | "args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
11 | "stopOnEntry": false,
12 | "sourceMaps": true,
13 | "outFiles": [ "${workspaceRoot}/out/**/*.js" ],
14 | "preLaunchTask": "npm: watch"
15 | },
16 | {
17 | "name": "Extension Tests",
18 | "type": "extensionHost",
19 | "request": "launch",
20 | "runtimeExecutable": "${execPath}",
21 | "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ],
22 | "stopOnEntry": false,
23 | "sourceMaps": true,
24 | "outFiles": [ "${workspaceRoot}/out/test/**/*.js" ],
25 | "preLaunchTask": "npm: watch"
26 | }
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/package.nls.json:
--------------------------------------------------------------------------------
1 | {
2 | "extension.preview.title": "vscode-preview-server: Preview on side panel",
3 | "extension.launch.title": "vscode-preview-server: Launch on browser",
4 | "extension.stop.title": "vscode-preview-server: Stop the web server",
5 | "extension.resume.title": "vscode-preview-server: Resume the web server",
6 | "extension.ui.title": "vscode-preview-server: Show UI Page",
7 | "previewServer.browsers.description": "Browsers to launch for preview.",
8 | "previewServer.ignoreDefaultBrowser.description": "Ignore default browsers.",
9 | "previewServer.ignoreNotification.description": "Controls wheter display notification or not.",
10 | "previewServer.isWatchConfiguration.description": "Controls whether resume the web Server or not, when change settings.",
11 | "previewServer.port.description": "Port number of the web Server.",
12 | "previewServer.proxy.description": "Wrap your vhost with a proxy URL to view your site.",
13 | "previewServer.startupProject.description": "Name of startup project. This setting is meaningful only when in the workspace.",
14 | "previewServer.sync.description": "Whether synchronized or not.",
15 | "previewServer.ui.description": "Settings for UI page."
16 | }
--------------------------------------------------------------------------------
/src/browserContentProvider.ts:
--------------------------------------------------------------------------------
1 | "use strict";
2 | import * as vscode from "vscode";
3 | import { Utility } from "./utility";
4 |
5 | export class BrowserContentProvider implements vscode.TextDocumentContentProvider {
6 | private _onDidChange = new vscode.EventEmitter();
7 |
8 | public provideTextDocumentContent() {
9 | const editor = vscode.window.activeTextEditor;
10 | const uri = Utility.getUriOfActiveEditor();
11 |
12 | if (editor.document.languageId !== "html") {
13 | return `
14 |
15 | Active editor doesn't show a HTML document
16 | `;
17 | }
18 |
19 | return `
20 |
21 |
22 |
23 |
24 |
25 | Preview
26 |
27 |
28 |
29 |
30 |
31 | `;
32 | }
33 |
34 | get onDidChange(): vscode.Event {
35 | return this._onDidChange.event;
36 | }
37 |
38 | public update(uri: vscode.Uri) {
39 | this._onDidChange.fire(uri);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## Release Notes
2 |
3 | ### 1.3.0
4 | - Change from using `vscode.open` to `openExternal` (#39)
5 | - Supported version is 1.35 or higher
6 |
7 | ### 1.2.1
8 | - improve preview layout (#35)
9 | - change the shortcut key (#36)
10 |
11 | ### 1.2.0
12 | - update minimum VS Code version to 1.23
13 | - change vscode.previewHtml to WebView #32
14 |
15 | ### 1.1.0
16 | - add notification option
17 | - update browser-sync
18 | - fix typo
19 |
20 | ### 1.0.1
21 | - support localization (japanese)
22 | - fix typo
23 |
24 | ### 1.0.0
25 | - support multi root folder
26 | - version up VS Code engine
27 | - add tag on Github
28 |
29 | ### 0.9.0
30 | - add browsers option
31 | - add ignoreDefaultBrowser option
32 | - add example of settings to README
33 | - add badges t0 README
34 |
35 | ### 0.8.0
36 | - support UI option
37 | - some tweaks
38 | - change README
39 |
40 | ### 0.7.0
41 | - support open file
42 |
43 | ### 0.6.2
44 | - set default background-color of side panel
45 | - fix typo
46 |
47 | ### 0.6.1
48 | - add isWatchConfiguration option
49 |
50 | ### 0.6.0
51 | - add random port feature
52 |
53 | ### 0.5.0
54 | - add proxy option
55 |
56 | ### 0.4.1
57 | - add shortcut key bindings.
58 |
59 | ### 0.4.0
60 | - change dependent package from node-static to browser-sync.
61 | - add auto-reload feature.
62 | - add sync option.
63 | - add resume command.
64 | - and a few tweaks.
65 |
66 | ### 0.3.1
67 | - show message when stop or resume the Web Server.
68 | - activate unit test.
69 |
70 | ### 0.3.0
71 | add featutre which stop the web server.
72 |
73 | ### 0.2.0
74 | publish to extension Marketplace.
75 |
76 | ### 0.1.0
77 | Initial upload. This extension haven't registered to Marketplace, yet.
--------------------------------------------------------------------------------
/src/server.ts:
--------------------------------------------------------------------------------
1 | import * as browserSync from "browser-sync";
2 | import { UiOption } from "./utility";
3 |
4 | export class Server {
5 |
6 | public static start(rootPath: string, port: number, isSync: boolean, proxy = "", ui: UiOption = null) {
7 | // get browserSync instance.
8 | let bs: browserSync.BrowserSyncInstance;
9 | if (!browserSync.has("vscode-preview-server")) {
10 | bs = browserSync.create("vscode-preview-server");
11 | } else {
12 | bs = browserSync.get("vscode-preview-server");
13 | }
14 |
15 | let options: browserSync.Options;
16 |
17 | if (proxy === "") {
18 | options = {
19 | server: {
20 | baseDir: rootPath,
21 | directory: true
22 | },
23 | open: false,
24 | port: port,
25 | codeSync: isSync
26 | };
27 | } else {
28 | options = {
29 | proxy: proxy,
30 | serveStatic: ["."]
31 | };
32 | }
33 |
34 | if (ui.port && ui.weinrePort) {
35 | options.ui = {
36 | port: ui.port,
37 | weinre: {
38 | port: ui.weinrePort
39 | }
40 | };
41 | }
42 |
43 |
44 | bs.init(options, (err) => {
45 | if (err) {
46 | console.log(err);
47 | bs.notify("Error is occured.");
48 | }
49 |
50 | });
51 | }
52 |
53 | public static stop() {
54 | if (browserSync.has("vscode-preview-server")) {
55 | browserSync.get("vscode-preview-server").exit();
56 | }
57 | }
58 |
59 | public static reload(fileName: string) {
60 | if (browserSync.has("vscode-preview-server")) {
61 | browserSync.get("vscode-preview-server").reload(fileName);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | const gulp = require("gulp");
2 | const path = require("path");
3 |
4 | const ts = require("gulp-typescript");
5 | const typescript = require("typescript");
6 | const sourcemaps = require("gulp-sourcemaps");
7 | const del = require("del");
8 | const es = require("event-stream");
9 | const vsce = require("vsce");
10 | const nls = require("vscode-nls-dev");
11 |
12 | const tsProject = ts.createProject("./tsconfig.json", { typescript });
13 |
14 | const inlineMap = true;
15 | const inlineSource = false;
16 | const outDest = "out";
17 |
18 | const languages = [{ folderName: 'jpn', id: 'ja' }];
19 |
20 | // ---- internal
21 |
22 | function compile(buildNls) {
23 | var r = tsProject.src()
24 | .pipe(sourcemaps.init())
25 | .pipe(tsProject()).js
26 | .pipe(buildNls ? nls.rewriteLocalizeCalls() : es.through())
27 | .pipe(buildNls ? nls.createAdditionalLanguageFiles(languages, "i18n", "out") : es.through());
28 |
29 | if (inlineMap && inlineSource) {
30 | r = r.pipe(sourcemaps.write());
31 | } else {
32 | r = r.pipe(sourcemaps.write("../out", {
33 | // no inlined source
34 | includeContent: inlineSource,
35 | // Return relative source map root directories per file.
36 | sourceRoot: "../src"
37 | }));
38 | }
39 |
40 | return r.pipe(gulp.dest(outDest));
41 | }
42 |
43 | gulp.task("internal-compile", function() {
44 | return compile(false);
45 | });
46 |
47 | gulp.task("internal-nls-compile", function() {
48 | return compile(true);
49 | });
50 |
51 | gulp.task("add-i18n", function() {
52 | return gulp.src(["package.nls.json"])
53 | .pipe(nls.createAdditionalLanguageFiles(languages, "i18n"))
54 | .pipe(gulp.dest("."));
55 | });
56 |
57 | gulp.task("vsce:publish", function() {
58 | return vsce.publish();
59 | });
60 |
61 | // ---- external
62 |
63 | gulp.task("clean", function() {
64 | return del(["out/**", "package.nls.*.json"]);
65 | });
66 |
67 | gulp.task("build", gulp.series("clean", "internal-nls-compile", "add-i18n"));
68 |
69 | gulp.task("compile", gulp.series("clean", "internal-compile"));
70 |
71 | gulp.task("publish", gulp.series("build", "vsce:publish"));
72 |
73 | gulp.task("default", gulp.series('build'));
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "jsRules": {
3 | "class-name": true,
4 | "comment-format": [
5 | true,
6 | "check-space"
7 | ],
8 | "indent": [
9 | true,
10 | "spaces"
11 | ],
12 | "no-duplicate-variable": true,
13 | "no-eval": true,
14 | "no-trailing-whitespace": true,
15 | "no-unsafe-finally": true,
16 | "one-line": [
17 | true,
18 | "check-open-brace",
19 | "check-whitespace"
20 | ],
21 | "quotemark": [
22 | true,
23 | "double"
24 | ],
25 | "semicolon": [
26 | true,
27 | "always"
28 | ],
29 | "triple-equals": [
30 | true,
31 | "allow-null-check"
32 | ],
33 | "variable-name": [
34 | true,
35 | "ban-keywords"
36 | ],
37 | "whitespace": [
38 | true,
39 | "check-branch",
40 | "check-decl",
41 | "check-operator",
42 | "check-separator",
43 | "check-type"
44 | ]
45 | },
46 | "rules": {
47 | "class-name": true,
48 | "comment-format": [
49 | true,
50 | "check-space"
51 | ],
52 | "eofline": true,
53 | "indent": [
54 | true,
55 | "spaces"
56 | ],
57 | "no-eval": true,
58 | "no-internal-module": true,
59 | "no-trailing-whitespace": true,
60 | "no-unsafe-finally": true,
61 | "no-var-keyword": true,
62 | "one-line": [
63 | true,
64 | "check-open-brace",
65 | "check-whitespace"
66 | ],
67 | "quotemark": [
68 | true,
69 | "double"
70 | ],
71 | "semicolon": [
72 | true,
73 | "always"
74 | ],
75 | "triple-equals": [
76 | true,
77 | "allow-null-check"
78 | ],
79 | "typedef-whitespace": [
80 | true,
81 | {
82 | "call-signature": "nospace",
83 | "index-signature": "nospace",
84 | "parameter": "nospace",
85 | "property-declaration": "nospace",
86 | "variable-declaration": "nospace"
87 | }
88 | ],
89 | "variable-name": [
90 | true,
91 | "ban-keywords"
92 | ],
93 | "whitespace": [
94 | true,
95 | "check-branch",
96 | "check-decl",
97 | "check-operator",
98 | "check-separator",
99 | "check-type"
100 | ]
101 | }
102 | }
--------------------------------------------------------------------------------
/src/utility.ts:
--------------------------------------------------------------------------------
1 | import { window, workspace, Uri } from "vscode";
2 |
3 | const opener = require("opener");
4 |
5 | export class Utility {
6 | public static getUriOfActiveEditor() {
7 | const fileName = window.activeTextEditor.document.fileName;
8 | const options = workspace.getConfiguration("previewServer");
9 | const port = options.get("port") as number;
10 | const proxy = options.get("proxy") as string;
11 | const space = this.checkSpace();
12 | let relativePath = workspace.asRelativePath(fileName);
13 |
14 | if (space === Space.File) {
15 | let paths = relativePath.split("\\");
16 | relativePath = paths[paths.length - 1];
17 | } else if (space === Space.Workspace) {
18 | relativePath = workspace.asRelativePath(fileName, false);
19 | }
20 |
21 | if (proxy === "") {
22 | return Uri.parse(`http://localhost:${port}/${relativePath}`);
23 | }
24 |
25 | let uri = Uri.parse(`http://${proxy}`);
26 | let host = uri.authority.split(":")[0];
27 | return Uri.parse(`http://${host}:3000/${uri.path}`);
28 | }
29 |
30 | public static setRandomPort() {
31 | const options = workspace.getConfiguration("previewServer");
32 | let port = options.get("port") as number;
33 | if (!port) {
34 | // dynamic ports (49152–65535)
35 | port = Math.floor(Math.random() * 16383 + 49152);
36 | options.update("port", port, false)
37 | .then(() => {
38 | window.showInformationMessage(`change previewServer.port setting to ${port}`);
39 | });
40 | }
41 | }
42 |
43 | public static openBrowser(browsers: string[]) {
44 |
45 | const url = decodeURIComponent(Utility.getUriOfActiveEditor().toString());
46 | browsers.forEach((browser) => {
47 | opener([browser, url]);
48 | });
49 | }
50 |
51 | /**
52 | * When vscode.workspace.rootPath is undefined (When we use `open file`, this value will be undefined),
53 | * we use filepath without file name.
54 | * @param relativePath
55 | */
56 | public static getOpenFilePath(relativePath: string) {
57 | let paths = relativePath.split("\\");
58 | // remove file name.
59 | paths.pop();
60 | return paths.join("\\");
61 | }
62 |
63 | public static checkSpace() {
64 | const folders = workspace.workspaceFolders;
65 | if (folders === undefined) {
66 | return Space.File;
67 | } else if (folders.length === 1) {
68 | return Space.Folder;
69 | } else {
70 | return Space.Workspace;
71 | }
72 | }
73 | }
74 |
75 | export interface UiOption {
76 | port: number;
77 | weinrePort: number;
78 | }
79 |
80 | export enum Space {
81 | File,
82 | Folder,
83 | Workspace
84 | }
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vscode-preview-server
2 |
3 | [](https://marketplace.visualstudio.com/items?itemName=yuichinukiyama.vscode-preview-server)
4 | [](https://marketplace.visualstudio.com/items?itemName=yuichinukiyama.vscode-preview-server)
5 | [](https://marketplace.visualstudio.com/items?itemName=yuichinukiyama.vscode-preview-server)
6 |
7 | ## Features
8 |
9 | This extension provide preview of HTML which execute on web server.
10 | When you save files, this extension automatically reload browser or side panel (live preview feature).
11 | You can call these features from the context menu or editor menu.
12 | The main features are as follows.
13 |
14 | * `Preview on side panel (ctrl+shift+v)`: Open preview of HTML on side panel. With this feature, you can easely check the operation of HTML, CSS and JavaScript.
15 | * `Launch on browser (ctrl+shift+l)`: Open Web Page on default browser. You can check all operation with web page.
16 | * `Stop the web server (ctrl+shift+s)`: Stop the web server. This feature can be used only from command palette.
17 | * `Resume the web server (ctrl+shift+r)`: Resume the web server. This feature can be used only from command palette.
18 | * `show UI Page (ctrl+shift+u)`: Show UI Page. You can change options at UI page.
19 |
20 | 
21 |
22 | ## Extension Settings
23 |
24 | ### Description
25 | This extension contributes the following settings:
26 |
27 | * `previewServer.browsers`: Browsers to launch. Even if you do not set this option, default browser launch if the ignoreDefaultBrowser is false. Default setting is *null*.
28 | * `previewServer.ignoreDefaultBrowser`: Controls whether launch default browser or not. Default setting is *false*.
29 | * `previewServer.isWatchConfiguration`: Controls whether resume the Web Server or not, when change settings. Default setting is *true*.
30 | * `previewServer.port`: Port number of the Web Server. If you set *null*, vscode-preview-server generate random number, and set port as random number. Default setting is *8080*.
31 | * `previewServer.proxy`: Set proxy. This is usefull when execute web app on another web server. Default setting is *""*.
32 | * `previewServer.sync`: Controls whether synchronized or not. Default setting is *true*.
33 | * `previewServer.ui`: Port number of UI Page. Default setting is *3001*.
34 | * `startupProject`: Name of startup project. This setting is meaningful only when in the workspace. This value is the name of the folder. When using this workspace and omitting this value, the first folder becomes the startup project Default setting is null. Customize this option if you would like to preview html from different workspaces.
35 |
36 | ### Simple example
37 |
38 | ```json
39 | {
40 | "previewServer.browsers": ["firefox", "chrome"],
41 | "previewServer.ignoreDefaultBroswer": true,
42 | "previewServer.port": 9999,
43 | "previewServer.ui": {
44 | "port": 3001,
45 | "weinrePort": 8081
46 | }
47 | }
48 | ```
49 |
50 | ### Settings with workspace
51 |
52 | ```json
53 | {
54 | "previewServer.startupProject": "Product"
55 | }
56 | ```
57 |
58 | ```json :sample.code-workspace
59 | {
60 | "folders": [
61 | {
62 | "name": "Product",
63 | "path": "foo"
64 | },
65 | {
66 | "name": "Test",
67 | "path": "bar"
68 | }
69 | ],
70 | "settings": {
71 | "previewServer.startupProject": "Product"
72 | }
73 | }
74 | ```
75 |
76 | ## How to build locally
77 |
78 | 1. Ensure that you have `gulp-cli` installed globally using `npm i -g gulp-cli`.
79 | 1. Run `npm install` to bring in the dependencies.
80 | 1. Run `gulp build` to produce i18n files.
81 | 1. Press `F5` key to launch extension.
82 |
83 |
84 | ## Known Issues
85 |
86 | `Preview on side panel` somethimes don't work with CDN, Link etc.
87 |
88 | ## Acknowledgements
89 | This extension use [browsersync](https://www.browsersync.io/).
90 | I would like to thank browsersync team for useful work.
91 |
92 | ## Lisence
93 | [MIT](https://github.com/YuichiNukiyama/vscode-preview-server/blob/master/LICENSE)
94 |
--------------------------------------------------------------------------------
/src/extension.ts:
--------------------------------------------------------------------------------
1 | import * as vscode from "vscode";
2 | import { BrowserContentProvider } from "./browserContentProvider";
3 | import { Server } from "./server";
4 | import { Utility, UiOption, Space } from "./utility";
5 | import * as nls from "vscode-nls";
6 |
7 | const localize = nls.config({locale: process.env.VSCODE_NLS_CONFIG})();
8 | const provider = new BrowserContentProvider();
9 |
10 | export function activate(context: vscode.ExtensionContext) {
11 | const options = vscode.workspace.getConfiguration("previewServer");
12 | const ignoreNotification = options.get("ignoreNotification") as boolean;
13 |
14 | // start web server
15 | startServer();
16 |
17 | // provider settings.
18 | const registration = vscode.workspace.registerTextDocumentContentProvider("preview", provider);
19 | vscode.workspace.onDidChangeTextDocument((e: vscode.TextDocumentChangeEvent) => {
20 | if (e.document === vscode.window.activeTextEditor.document) {
21 | const previewUri = Utility.getUriOfActiveEditor();
22 | provider.update(previewUri);
23 | }
24 | });
25 |
26 | // When configuration is changed, resume web server.
27 | vscode.workspace.onDidChangeConfiguration(() => {
28 | const settings = vscode.workspace.getConfiguration("previewServer")
29 | .get("isWatchConfiguration") as boolean;
30 | if (settings) {
31 | resumeServer();
32 | if (!ignoreNotification){
33 | vscode.window.showInformationMessage(localize("resumeServer.text", "Resume the Web Server."));
34 | }
35 | }
36 | });
37 |
38 | // When file is saved, reload browser.
39 | vscode.workspace.onDidSaveTextDocument((e) => {
40 | Server.reload(e.fileName);
41 | });
42 |
43 | let disposable: any = vscode.commands.registerCommand("extension.preview", () => {
44 | // set ViewColumn
45 | let viewColumn: vscode.ViewColumn;
46 |
47 | if (vscode.window.activeTextEditor.viewColumn < 3) {
48 | viewColumn = vscode.window.activeTextEditor.viewColumn + 1;
49 | } else {
50 | viewColumn = 1;
51 | }
52 |
53 | const panel = vscode.window.createWebviewPanel("preview-server", "Preview", viewColumn, {
54 | enableScripts: true,
55 | retainContextWhenHidden: true
56 | });
57 | panel.webview.html = provider.provideTextDocumentContent();
58 |
59 | });
60 |
61 | let disposable2: any = vscode.commands.registerCommand("extension.launch", () => {
62 | const uri = Utility.getUriOfActiveEditor();
63 | const options = vscode.workspace.getConfiguration("previewServer");
64 | const browsers = options.get("browsers") as string[];
65 | const ignoreDefaultBrowser = options.get("ignoreDefaultBrowser") as boolean;
66 |
67 | if (browsers === null && !ignoreDefaultBrowser) {
68 | return vscode.env.openExternal(uri);
69 | } else if (browsers !== null && !ignoreDefaultBrowser) {
70 | Utility.openBrowser(browsers);
71 | return vscode.env.openExternal(uri);
72 | } else if (browsers !== null && ignoreDefaultBrowser) {
73 | return Utility.openBrowser(browsers);
74 | } else {
75 | return vscode.window.showErrorMessage(localize("launchError.text", "You should set browser option or change ignoreDefultBrowser to true."));
76 | }
77 | });
78 |
79 | let disposable3: any = vscode.commands.registerCommand("extension.stop", () => {
80 | Server.stop();
81 | if (!ignoreNotification) {
82 | vscode.window.showInformationMessage(localize("stopServer.text", "Stop the Web Server successfully."));
83 | }
84 | });
85 |
86 | let disposable4: any = vscode.commands.registerCommand("extension.resume", () => {
87 | resumeServer();
88 | if (!ignoreNotification) {
89 | vscode.window.showInformationMessage(localize("resumeServer.text2", "Resume the Web Server."));
90 | }
91 | });
92 |
93 | let disposable5: any = vscode.commands.registerCommand("extension.ui", () => {
94 | let port = 3001;
95 | const ui = vscode.workspace.getConfiguration("previewServer").get("ui") as UiOption;
96 |
97 | if (ui.port) {
98 | port = ui.port;
99 | }
100 |
101 | const uri = vscode.Uri.parse(`http://localhost:${port}`);
102 | return vscode.env.openExternal(uri);
103 | });
104 |
105 | context.subscriptions.push(vscode.workspace.onDidChangeWorkspaceFolders(() => resumeServer()));
106 | context.subscriptions.push(disposable, disposable2, disposable3, disposable4, disposable5, registration);
107 | }
108 |
109 | function startServer() {
110 | Utility.setRandomPort();
111 | const options = vscode.workspace.getConfiguration("previewServer");
112 | const port = options.get("port") as number;
113 | const proxy = options.get("proxy") as string;
114 | const isSync = options.get("sync") as boolean;
115 | const ignoreNotification = options.get("ignoreNotification") as boolean;
116 | const ui = options.get("ui") as UiOption;
117 | const startupProject = options.get("startupProject") as string;
118 | const space = Utility.checkSpace();
119 | let rootPath = "";
120 |
121 | if (space === Space.File) {
122 | rootPath = Utility.getOpenFilePath(vscode.window.activeTextEditor.document.fileName);
123 | } else if (space === Space.Folder || (space === Space.Workspace && !startupProject)) {
124 | rootPath = vscode.workspace.workspaceFolders[0].uri.fsPath;
125 | } else {
126 | for (let folder of vscode.workspace.workspaceFolders) {
127 | const workspaceName = vscode.workspace.getWorkspaceFolder(folder.uri).name;
128 | if (workspaceName === startupProject) {
129 | rootPath = folder.uri.fsPath;
130 | break;
131 | }
132 | }
133 |
134 | if (rootPath === "" && !ignoreNotification) {
135 | vscode.window.showErrorMessage(localize("startupProjectError.text", "startupProject option is null or invalide value."));
136 | }
137 | }
138 |
139 | Server.start(rootPath, port, isSync, proxy, ui);
140 | }
141 |
142 | function resumeServer() {
143 | Server.stop();
144 | startServer();
145 | }
146 |
147 | export function deactivate() {
148 | Server.stop();
149 | }
150 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vscode-preview-server",
3 | "displayName": "Preview on Web Server",
4 | "description": "Preview Web Page on Web Server.",
5 | "version": "1.3.0",
6 | "publisher": "yuichinukiyama",
7 | "author": {
8 | "name": "Yuichi Nukiyama"
9 | },
10 | "license": "MIT",
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/YuichiNukiyama/vscode-preview-server"
14 | },
15 | "bugs": {
16 | "url": "https://github.com/YuichiNukiyama/vscode-preview-server/issues"
17 | },
18 | "engines": {
19 | "vscode": "^1.35.0"
20 | },
21 | "categories": [
22 | "Other"
23 | ],
24 | "keywords": [
25 | "HTML",
26 | "Preview",
27 | "VSCode",
28 | "multi-root ready"
29 | ],
30 | "icon": "images/icon.png",
31 | "activationEvents": [
32 | "onCommand:extension.preview",
33 | "onCommand:extension.launch",
34 | "onCommand:extension.stop",
35 | "onCommand:extension.resume",
36 | "onCommand:extension.ui"
37 | ],
38 | "main": "./out/src/extension",
39 | "contributes": {
40 | "configuration": {
41 | "type": "object",
42 | "title": "PreviewServer",
43 | "properties": {
44 | "previewServer.browsers": {
45 | "type": "array",
46 | "default": null,
47 | "description": "%previewServer.browsers.description%",
48 | "items": {
49 | "type": "string",
50 | "enum": [
51 | "firefox",
52 | "chrome",
53 | "opera",
54 | "safari"
55 | ]
56 | }
57 | },
58 | "previewServer.ignoreDefaultBrowser": {
59 | "type": "boolean",
60 | "default": false,
61 | "description": "%previewServer.ignoreDefaultBrowser.description%"
62 | },
63 | "previewServer.ignoreNotification": {
64 | "type": "boolean",
65 | "default": false,
66 | "description": "%previewServer.ignoreNotification.description%"
67 | },
68 | "previewServer.isWatchConfiguration": {
69 | "type": "boolean",
70 | "default": true,
71 | "description": "%previewServer.isWatchConfiguration.description%"
72 | },
73 | "previewServer.port": {
74 | "type": [
75 | "number",
76 | "null"
77 | ],
78 | "default": 8080,
79 | "description": "%previewServer.port.description%"
80 | },
81 | "previewServer.proxy": {
82 | "type": "string",
83 | "default": "",
84 | "description": "%previewServer.proxy.description%"
85 | },
86 | "previewServer.startupProject": {
87 | "type": "string",
88 | "default": null,
89 | "description": "%previewServer.startupProject.description%"
90 | },
91 | "previewServer.sync": {
92 | "type": "boolean",
93 | "default": true,
94 | "description": "%previewServer.sync.description%"
95 | },
96 | "previewServer.ui": {
97 | "type": "object",
98 | "description": "%previewServer.ui.description%",
99 | "properties": {
100 | "port": {
101 | "type": "number",
102 | "default": 3001,
103 | "description": "Port number of UI."
104 | },
105 | "weinrePort": {
106 | "type": "number",
107 | "default": 8081,
108 | "description": "Port number of weinre."
109 | }
110 | }
111 | }
112 | }
113 | },
114 | "commands": [
115 | {
116 | "command": "extension.preview",
117 | "title": "%extension.preview.title%"
118 | },
119 | {
120 | "command": "extension.launch",
121 | "title": "%extension.launch.title%"
122 | },
123 | {
124 | "command": "extension.stop",
125 | "title": "%extension.stop.title%"
126 | },
127 | {
128 | "command": "extension.resume",
129 | "title": "%extension.resume.title%"
130 | },
131 | {
132 | "command": "extension.ui",
133 | "title": "%extension.ui.title%"
134 | }
135 | ],
136 | "keybindings": [
137 | {
138 | "command": "extension.preview",
139 | "key": "ctrl+shift+v"
140 | },
141 | {
142 | "command": "extension.launch",
143 | "key": "ctrl+shift+l"
144 | },
145 | {
146 | "command": "extension.stop",
147 | "key": "ctrl+shift+s"
148 | },
149 | {
150 | "command": "extension.resume",
151 | "key": "ctrl+shift+r"
152 | },
153 | {
154 | "command": "extension.ui",
155 | "key": "ctrl+shift+u"
156 | }
157 | ],
158 | "menus": {
159 | "explorer/context": [
160 | {
161 | "command": "extension.preview",
162 | "when": "resourceLangId == html"
163 | },
164 | {
165 | "command": "extension.launch",
166 | "when": "resourceLangId == html"
167 | }
168 | ],
169 | "editor/context": [
170 | {
171 | "command": "extension.preview",
172 | "when": "resourceLangId == html"
173 | },
174 | {
175 | "command": "extension.launch",
176 | "when": "resourceLangId == html"
177 | }
178 | ]
179 | }
180 | },
181 | "scripts": {
182 | "vscode:prepublish": "npm run compile",
183 | "compile": "tsc -p ./",
184 | "watch": "tsc -watch -p ./",
185 | "postinstall": "node ./node_modules/vscode/bin/install",
186 | "test": "node ./node_modules/vscode/bin/test"
187 | },
188 | "devDependencies": {
189 | "@types/browser-sync": "0.0.41",
190 | "@types/mocha": "^2.2.48",
191 | "@types/node": "^7.0.70",
192 | "@types/opener": "^1.4.0",
193 | "del": "^3.0.0",
194 | "event-stream": "3.3.4",
195 | "gulp": "^4.0.1",
196 | "gulp-filter": "^5.1.0",
197 | "gulp-typescript": "^5.0.1",
198 | "mocha": "^5.2.0",
199 | "run-sequence": "^2.2.1",
200 | "ts-loader": "^5.4.4",
201 | "tslint": "^4.5.1",
202 | "typescript": "^3.4.5",
203 | "vsce": "^1.50.0",
204 | "vscode": "^1.1.36",
205 | "vscode-nls-dev": "^3.2.2",
206 | "webpack": "^4.30.0",
207 | "webpack-cli": "^3.3.1"
208 | },
209 | "dependencies": {
210 | "browser-sync": "^2.26.7",
211 | "gulp-sourcemaps": "^2.6.5",
212 | "opener": "^1.5.1",
213 | "vscode-nls": "^4.0.0"
214 | }
215 | }
216 |
--------------------------------------------------------------------------------