Webpack, Uikit, multi-language static website
If you want to build a custom website theme the best framework for this is Uikit, I used it the past for some of my projects and is great. In order to setup your environment and start customizing your theme you need a build system, and for that Webpack is a good choice.
TL;DR
Check out this github.com/gabihodoroaga/webpack-uikit-translate repository if you want to get started to create a new Uikit website or theme.
Prerequisites
The project setup
Let’s start from the beginning and initialize our repository,
npm init
and complete all the required fields.
Next let’s add our dependencies
npm install webpack webpack-cli webpack-dev-server \
url-loader typescript ts-loader style-loader \
sass-loader sass mini-css-extract-plugin \
html-webpack-plugin file-loader html-loader \
css-loader copy-webpack-plugin clean-webpack-plugin \
@types/lodash --save-dev
add configure out build system; add a file named webpack.config.js with the following content
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyPlugin = require('copy-webpack-plugin');
const path = require("path");
const devMode = process.env.NODE_ENV !== 'production';
const plugins = [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "src", "index.html")
})
];
if (!devMode) {
plugins.push(new MiniCssExtractPlugin({ filename: "styles.[fullhash].css" }));
}
const webpackConfig = {
entry: './src/index.ts',
output: {
filename: 'bundle.[fullhash].js',
path: path.resolve(__dirname, 'dist'),
},
plugins: plugins,
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
exclude: "/node_modules/"
},
{
test: /\.scss$/,
use: [
devMode ? 'style-loader' : {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: ''
}
},
"css-loader",
"sass-loader"
]
},
{
test: /\.(woff|woff2|ttf|eot)$/,
loader: 'file-loader',
options: {
name: 'assets/fonts/[name].[ext]'
}
},
{
test: /\.(jpe?g|png|gif|svg)$/,
loader: 'url-loader',
}
]
},
resolve: {
extensions: [".ts", ".tsx", ".js"]
}
};
module.exports = function(env)
{
return webpackConfig;
};
and the tsconfig.json file
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "es6",
"target": "es5",
"allowJs": false
},
"exclude": [
"node_modules"
]
}
Webpack entry point is src/index.ts so let’s create this this file also
import "./style.scss";
and the src/style.scss
body {
background-color: lightgray;
}
and the src/index.html of course because what is a website without the index.html
<!doctype html>
<html lang="en" class="uk-notouch" dir="ltr">
<head>
</head>
<body>
</body>
</html>
Now we need to add some scripts to the package.json
...
"scripts": {
"dev": "webpack --mode development",
"start": "webpack serve",
"build": "export NODE_ENV=production && webpack --mode production"
},
...
You can test your setup by running
npm start
Uikit
Uikit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.
Let’s add Uikit to out dependencies list, we will to the dev dependencies because we will bundle out UiKit together with our website
npm install uikit --save-dev
We need to update the src/index.ts file to include the uikit files
// @ts-ignore
import UIkit from 'uikit';
// @ts-ignore
import Icons from 'uikit/dist/js/uikit-icons';
// loads the Icon plugin
UIkit.use(Icons);
and the the src/style.scss file
// 1. Your custom variables and variable overwrites.
$base-body-background: lightgray;
// 2. Import default variables and available mixins.
@import "uikit/src/scss/variables-theme.scss";
@import "uikit/src/scss/mixins-theme.scss";
// 3. Your custom mixin overwrites.
// 4. Import UIkit.
@import "uikit/src/scss/uikit-theme.scss";
and more meaningful elements to the /src/index.html file
<body>
<nav class="uk-navbar-container" uk-navbar>
<div class="uk-navbar-left">
<ul class="uk-navbar-nav">
<li class="uk-active"><a href="#">Active</a></li>
<li>
<a href="#">Parent</a>
<div class="uk-navbar-dropdown">
<ul class="uk-nav uk-navbar-dropdown-nav">
<li class="uk-active"><a href="#">Active</a></li>
<li><a href="#">Item</a></li>
<li><a href="#">Item</a></li>
</ul>
</div>
</li>
<li><a href="#">Item</a></li>
</ul>
</div>
</nav>
</body>
Translations
In order to be able to create localizable versions of our website we need 2 more packages
This gulp plugin that extracts localizable content from HTML templates into a JSON file that can be sent to translators. Once translated, the content can then be injected back into the templates as part of a localized build process, or just served to the client.
Webpack loader that localizes HTML templates and JSON files by injecting translated content, replacing the original content that was previously exported for translation.
npm install gulp-translate translation-loader globs --save-dev
and we need to add 2 more files, one file to define our translation configurations translate-config.js
module.exports =
{
normalizeContent: true,
prefixIdsInContentFiles: true,
baseFilePath: "./src",
allowDirectAnnotation: true,
exportFilePath: "./src/translation/export/translate.json",
importFilePath: "./src/translation/import/{locale}.json",
includedFilePaths: [
"./src/**/*.html",
],
excludedFilePaths:[
]
};
and a helper script to export our translations translate-export.js
const fs = require("fs");
const globs = require("globs");
const translatePlugin = require("gulp-translate/lib/plugin/plugin");
const translateConfig = require("./translate-config");
// Get the source file paths.
const filePaths = globs.sync(translateConfig.includedFilePaths,
{
ignore: translateConfig.excludedFilePaths
});
// Create the export task.
const plugin = new translatePlugin.Plugin(translateConfig);
const task = plugin.export(translateConfig);
// Process the source files.
for (let filePath of filePaths)
{
const fileContents = fs.readFileSync(filePath);
const file = { contents: fileContents, path: filePath };
task.process(file);
}
// Finalize the export task.
task.finalize();
Now we need to update our webpack.config.js to handle translations
...
const translateConfig = require("./translate-config");
...
rules: [
{
test: /\.html$/,
use:
[
{ loader: "html-loader" },
{ loader: "translation-loader", options: translateConfig }
]
},
...
module.exports = function(env)
{
if (env && env.locale)
{
translateConfig.importFilePath =
translateConfig.importFilePath.replace("{locale}", env.locale);
webpackConfig.output.path += `/${env.locale}`
}
else
{
translateConfig.excludedFilePaths = ["**"];
}
return webpackConfig;
};
and add more scripts to the package.json file
...
"scripts": {
...
"tr-export": "node translate-export",
"dev-es": "webpack --mode development --env locale=es",
"start-es": "webpack serve --env locale=es",
"build-es": "export NODE_ENV=production && webpack --mode production --env locale=es",
"build-all": "npm run build && npm run build-es",
},
In order to tell the gulp plugin what is translatable content and how extract it we need to add custom attributes to src/index.html file:
...
<ul class="uk-navbar-nav">
<li class="uk-active" translate><a href="#">Active</a></li>
<li>
<a href="#" translate>Parent</a>
<div class="uk-navbar-dropdown">
<ul class="uk-nav uk-navbar-dropdown-nav">
<li class="uk-active"><a href="#" translate>Active</a></li>
<li><a href="#" translate>Item</a></li>
<li><a href="#" translate>Item</a></li>
</ul>
</div>
</li>
<li><a href="#" translate>Item</a></li>
</ul>
...
Ok. We are ready to create our Spanish version of out website. First export your translations
npm run tr-export
and then create a new file src/translation/import/es.json with the this content
{
"53e6e2910": "<a href=\"#\">Activo</a>",
"bcf5c8ea0": "Principal",
"43b6016f2": "Activo",
"ab12e73f5": "Elemento"
}
If you run
npm run start-es
you should be able to see the Spanish version of your website.
Troubleshooting
If you see this error:
1 ERROR in child compilations.
webpack 5.6.0 compiled with 1 error in 7070 ms
and you have no idea what the error is, then you can try this:
- disable/comment the HtmlWebpackPlugin from webpack.config.json
- add import “./index.html” to “src/index.ts”
- run “npm run start-es”
Conclusion
You can download this startup project from github.com/gabihodoroaga/webpack-uikit-translate and start working on you custom website design.