Search code examples
typescriptwebpackcodemirror

CodeMirror with Vanilla TypeScript and WebPack


I am trying to use CodeMirror in a vanilla TypeScript JavaScript application (no React or Angular but with Bootstrap 4 as the CSS framework) using WebPack module bundler.

Application Code

import * as CodeMirror from 'codemirror';
import 'codemirror/mode/xml/xml.js';
import 'codemirror/theme/blackboard.css';

const definition: HTMLTextAreaElement = document.getElementById('Definition')
   as HTMLTextAreaElement;

const config: CodeMirror.EditorConfiguration = {
    tabSize: 3,
    lineNumbers: true,
    mode: 'xml',
    theme: 'blackboard'
};

const editor = CodeMirror.fromTextArea(definition, config);

package.json

{
    "dependencies": {
        "@types/codemirror": "0.0.72",
        "@types/jquery": "^3.3.22",
        "bootstrap": "^4.1.3",
        "codemirror": "^5.45.0",
        "font-awesome": "^4.7.0",
        "jquery": "^3.3.1",
        "popper": "^1.0.1",
        "popper.js": "^1.14.6"
    },
    "devDependencies": {
        "@babel/core": "^7.1.6",
        "@babel/preset-env": "^7.1.6",
        "autoprefixer": "^9.3.1",
        "babel-loader": "^8.0.4",
        "clean-webpack-plugin": "^0.1.19",
        "copy-webpack-plugin": "^4.6.0",
        "css-loader": "^1.0.1",
        "cssnano": "^4.1.7",
        "extract-text-webpack-plugin": "^3.0.2",
        "fetch": "^1.1.0",
        "file-loader": "^2.0.0",
        "font-awesome-loader": "^1.0.2",
        "html-webpack-plugin": "^3.2.0",
        "json-loader": "^0.5.7",
        "mini-css-extract-plugin": "^0.4.5",
        "node-sass": "^4.10.0",
        "optimize-css-assets-webpack-plugin": "^5.0.1",
        "postcss-loader": "^3.0.0",
        "precss": "^3.1.2",
        "raw-loader": "^0.5.1",
        "sass-loader": "^7.1.0",
        "style-loader": "^0.23.1",
        "ts-loader": "^5.3.1",
        "typescript": "^3.2.1",
        "uglifyjs-webpack-plugin": "^2.0.1",
        "url-loader": "^1.1.2",
        "webpack": "^4.27.0",
        "webpack-cli": "^3.1.2",
        "webpack-node-externals": "^1.7.2"
    }
}

webpack.config (Rules Section)

rules: [
    // JavaScript
    {
        test: /\.jsx?$/, // JavaScript and Reactive JavaScript
        exclude: /node_modules/,
        use: {
            loader: 'babel-loader', // Transpiles ES6 JavaScript files
            options: {
                presets: ['@babel/preset-env']
            }
        }
    },

    // TypeScript
    {
        test: /\.tsx?$/,
        loader: 'ts-loader',
        exclude: /node_modules/
    },

    // CSS
    {
        test: /\.css$/,
        use: ['style-loader', 'css-loader', 'postcss-loader']
    }
]

The application compiles and builds without error and there are no console logging errors, but the CodeMirror layout is broken:enter image description here

Any advice/direction on where I am going wrong would be much appreciated.


Solution

  • I eventually got this to work. The problem was related to my webpack.config, specifically that I needed to configure postcss plugin. Here is my working code.

    Note, I cannot guarantee the efficiency of the approach or the output, but at least I have it working. If anyone can suggest an alternative/better approach please let me know. Thanks.

    package.json

    "postcss": {
        "plugins": {
            "postcss-plugin": {}
        }
    }
    

    webpack.config

    {
        test: /\.css$/,
        use: [
            'style-loader',
            { loader: 'css-loader', options: { importLoaders: 1 } },
            'postcss-loader'
        ]
    },
    

    CodeMirror.ts

    import * as CodeMirror from 'codemirror';
    import 'codemirror/lib/codemirror.css';
    import 'codemirror/addon/display/fullscreen.css';
    import 'codemirror/theme/neat.css';
    import 'codemirror/mode/xml/xml.js';
    import 'codemirror/addon/display/fullscreen.js';
    import '../../styles/components/_codemirror.css';
    
    
    export class CodeMirrorManager {
    
        public editor: CodeMirror.Editor;
    
        config: CodeMirror.EditorConfiguration = {
            tabSize: 3,
            lineNumbers: true,
            mode: 'xml',
            theme: 'neat',
            extraKeys: {
                "F11": function (cm) {
                    if (cm.getOption("fullScreen")) {
                        cm.setOption("fullScreen", false);
                    } else {
                        cm.setOption("fullScreen", true);
                    }
                },
                "Esc": function (cm) {
                    if (cm.getOption("fullScreen")) {
                        cm.setOption("fullScreen", false);
                    }
                }
            }
        };
    
        // CTOR
        constructor(private readonly tagElement: HTMLTextAreaElement) {
            this.editor = CodeMirror.fromTextArea(this.tagElement, this.config);
        }
    }