diff --git a/client/app/visualizations/variables.less b/viz-lib/src/visualizations/variables.less
similarity index 100%
rename from client/app/visualizations/variables.less
rename to viz-lib/src/visualizations/variables.less
diff --git a/client/app/visualizations/visualizationsSettings.js b/viz-lib/src/visualizations/visualizationsSettings.js
similarity index 100%
rename from client/app/visualizations/visualizationsSettings.js
rename to viz-lib/src/visualizations/visualizationsSettings.js
diff --git a/client/app/visualizations/word-cloud/Editor.jsx b/viz-lib/src/visualizations/word-cloud/Editor.jsx
similarity index 100%
rename from client/app/visualizations/word-cloud/Editor.jsx
rename to viz-lib/src/visualizations/word-cloud/Editor.jsx
diff --git a/client/app/visualizations/word-cloud/Renderer.jsx b/viz-lib/src/visualizations/word-cloud/Renderer.jsx
similarity index 100%
rename from client/app/visualizations/word-cloud/Renderer.jsx
rename to viz-lib/src/visualizations/word-cloud/Renderer.jsx
diff --git a/client/app/visualizations/word-cloud/index.js b/viz-lib/src/visualizations/word-cloud/index.js
similarity index 100%
rename from client/app/visualizations/word-cloud/index.js
rename to viz-lib/src/visualizations/word-cloud/index.js
diff --git a/client/app/visualizations/word-cloud/renderer.less b/viz-lib/src/visualizations/word-cloud/renderer.less
similarity index 100%
rename from client/app/visualizations/word-cloud/renderer.less
rename to viz-lib/src/visualizations/word-cloud/renderer.less
diff --git a/viz-lib/webpack.config.js b/viz-lib/webpack.config.js
new file mode 100644
index 0000000000..72ba2258c1
--- /dev/null
+++ b/viz-lib/webpack.config.js
@@ -0,0 +1,65 @@
+const LessPluginAutoPrefix = require("less-plugin-autoprefix");
+const path = require("path");
+
+const isProduction = process.env.NODE_ENV === "production";
+
+module.exports = {
+ mode: isProduction ? "production" : "development",
+ entry: "./src/index.js",
+ output: {
+ path: path.resolve(__dirname, "dist"),
+ filename: "redash-visualizations.js",
+ libraryTarget: "umd",
+ },
+ resolve: {
+ symlinks: false,
+ extensions: [".js", ".jsx"],
+ },
+ module: {
+ rules: [
+ {
+ test: /\.jsx?$/,
+ exclude: /node_modules/,
+ use: ["babel-loader"],
+ },
+ {
+ test: /\.css$/,
+ use: ["style-loader", "css-loader"],
+ },
+ {
+ test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
+ use: [
+ {
+ loader: "file-loader",
+ options: {
+ outputPath: "images/",
+ name: "[name].[ext]",
+ },
+ },
+ ],
+ },
+ {
+ test: /\.less$/,
+ use: [
+ "style-loader",
+ "css-loader",
+ {
+ loader: "less-loader",
+ options: {
+ plugins: [new LessPluginAutoPrefix({ browsers: ["last 3 versions"] })],
+ javascriptEnabled: true,
+ },
+ },
+ ],
+ },
+ ],
+ },
+ externals: [
+ {
+ lodash: "lodash",
+ react: "react",
+ "react-dom": "react-dom",
+ },
+ /^antd/i,
+ ],
+};