vue-gettext
July 3, 2020 · View on GitHub
Table of contents
Project structure
.
├── build/ # Build and environment config files.
├── dev/ # Files used for the development of the plugin.
├── dist/ # The production version of the plugin.
├── src/ # Source code of the plugin.
├── test/ # Unit tests.
├── .babelrc # Babel config
├── .eslintrc.js # Eslint config
├── Makefile # A Makefile to extract translations and generate .po files
└── package.json # Build scripts and dependencies
Dev setup
Node v10+ is required for development.
# install deps
npm install
# serve examples at localhost:8080
npm run dev
# lint & run all tests
npm run test
Pull request guidelines
- explain why/what you are doing in the PR description, so that anybody can quickly understand what you want
- all development should be done in dedicated branches
- do not touch files in
distbecause they are automatically generated at release time - add accompanying test case(s)
- make sure
npm testpasses
Implementation notes
Version number
I changed the plugin version number to 2.x to match Vue.js 2.0 version.
New component tag name
By popular demand, <get-text> has been renamed <translate>.
Interpolation in the <translate> component
Interpolation inside attributes are deprecated in Vue 2. See my question on the Vue.js forum:
This breaks the old vue-gettext 1 component.
The solution I have reached is to use a set of custom delimiters for placeholders in component templates together with a custom interpolation function, e.g.:
<translate>Hello %{name}, I am the translation key!</translate>
↓
Hello %{name}, I am the translation key!
↓
Hello John, I am the translation key!
Drawbacks:
vue-gettext 2works only with Vue 2.0- it add a minimal hook to your templates code
But it works very well while waiting for something better. Practicality beats purity I guess.
Dev setup notes
My notes about the plugin setup.
I wanted to explore the Webpack ecosystem and some choices made in the Webpack template for vue-cli.
npm's package.json:
1) Webpack and HMR (Hot Module Replacement)
express
html-webpack-plugin
webpack
webpack-dev-middleware
webpack-hot-middleware
npm install --save-dev express html-webpack-plugin webpack webpack-dev-middleware webpack-hot-middleware
Webpack is a module bundler. It takes a bunch of files (JS, CSS, Images, HTML etc.), treating each as a module, figuring out the dependencies between them, and bundle them into static assets that are ready for deployment.
"Hot Module Replacement" (HMR) is a Webpack development feature to inject updated modules into the active runtime.
There are 3 ways to set up HMR.
We use webpack-hot-middleware
to run a Webpack dev server with HMR inside an express
server. Compilation should be faster because the packaged files are written
to memory rather than to disk.
In Express, a middleware is a function that receives the request and response objects of an HTTP request/response cycle. It may modify (transform) these objects before passing them to the next middleware function in the chain. It may decide to write to the response; it may also end the response without continuing the chain.
The Webpack Hot Middleware installs itself as a Webpack plugin, and listens for compiler events. Each connected client gets a Server Sent Events connection, the server will publish notifications to connected clients on compiler events. When the client receives a message, it will check to see if the local code is up to date. If it isn't up to date, it will trigger Webpack Hot Module Replacement.
HMR is opt-in, so we also need to put some code at chosen points of our
application. This had not yet been done since we have to dive into the
HMR JavaScript API (but state preserving hot-reload is implemented in
vue-webpack-boilerplate).
The HTML Webpack Plugin
will generate an index.html entry point to our application, and auto inject
our Webpack bundles. This is especially useful for multiple environment builds,
to stop the HTML getting out of sync between environments, avoiding
hard-written paths and simplifying the cache busting process. Here's how the
entry point is automatically added: in Webpack there is a make plugin hook
on the compilation in which entry points can be added ; see
this,
this
and this.
Note: the Webpack template serves static files with Express.
- Webpack — Concepts
- Webpack — Configuration
- Webpack — The Missing Tutorial
- Webpack — The Confusing Parts
- Webpack + Express — The simplest Webpack and Express setup
- HMR — Hot Module Replacement with Webpack
- HMR — Understanding Webpack HMR
- HMR — Webpack HMR Tutorial
- HMR — Webpack Middleware and Hot Module Replacement
2) Splitting the Webpack configuration for multiple environments
There are several ways of splitting the Webpack configuration for multiple environments.
Some people prefer maintaining configuration
within a single file and branch there,
other prefer partial configurations files
that then can be merged together using specialized tools like
webpack-merge.
We took a different approach here: one file per environment, because we don't provide production environment so we just have one file for the development environment. The distribution build is made with Rollup (cf section 11 of this file).
The current environment is set in an environment variable. Node.js provides the
process.env property
containing the user environment and NODE_ENV
is an environment variable made popular by the Express webserver framework.
If NODE_ENV is not set explicitly, it will be undefined. So we explicitly set
it in JavaScript for the Express application, e.g.:
process.env.NODE_ENV = 'development'.
Sometimes we also need to use environment variables (or other constants) in the
client code. They can be exposed as global constants via
webpack.DefinePlugin.
- NodeJs Best Practices: Environment-Specific Configuration
- Simple production environment with Webpack and Express
- How to load different .env.json files into the app depending on environment
- Why does Webpack's DefinePlugin require us to wrap everything in JSON.stringify?
3) Linting with ESLint
eslint
eslint-config-standard
eslint-plugin-promise // Required by `eslint-config-standard`.
eslint-plugin-standard // Required by `eslint-config-standard`.
npm install --save-dev eslint eslint-config-standard eslint-plugin-promise eslint-plugin-standard
We use the Standard preset with some small customizations, see rules
in .eslintrc.js.
Note: I'm using the JavaScript ESLint TextMate Bundle, in a personal capacity.
- ESLint
- Configuring ESLint
- JavaScript Standard Style
eslint-config-standard- ESLint Shareable Config
4) Linting with Webpack
eslint-loader
eslint-friendly-formatter
npm install --save-dev eslint-loader eslint-friendly-formatter
5) Babel
babel-core // Babel compiler core.
babel-loader // Allows transpiling JavaScript files using Babel and Webpack.
babel-preset-es2015 // ES6/ES2015 support.
babel-plugin-transform-runtime // Avoid repeated inclusion of Babel's helper functions.
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-plugin-transform-runtime
See the Babel configuration in
.babelrc.
- Setting up ES6
- Babel
- Clearing up the Babel 6 Ecosystem
- Using ES6 and ES7 in the Browser, with Babel 6 and Webpack
- The Six Things You Need To Know About Babel 6
6) Vue.js
vue
npm install --save-dev vue
We use the standalone build which includes the compiler and supports the template option.
7) Vue loader
vue-loader
vue-template-compiler
eslint-plugin-html
npm install --save-dev vue-loader vue-template-compiler eslint-plugin-html
vue-loader is a loader for Webpack that can transform Vue components into a
plain JavaScript module.
Since Vue 2.1.0, vue-template-compiler is a peer dependency of vue-loader instead of a direct dependency.
We also need the eslint-html-plugin
with supports extracting and linting the JavaScript inside *.vue files and
enable it
in the .eslintrc.js config file.
8) Common loaders
html-loader
json-loader
npm install --save-dev html-loader json-loader
9) CSS
style-loader // Adds CSS to the DOM by injecting a style tag.
css-loader
postcss-loader
postcss-cssnext
postcss-import
npm install --save-dev css-loader style-loader postcss-loader postcss-cssnext postcss-import
This is how I use scoped CSS in components for the development of the plugin:
Component's styles are locally scoped in each of them to avoid class name
conflicts. This is done via
css-loader's Local scope.
The PostCSS-cssnext syntax is used across components:
it's a PostCSS plugin that let us
use the latest CSS syntax today.
postcss-import lets us import
CSS variables like this: @import './styles/variables.css';.
There are other way to scope CSS:
Note: CSS are buried inside our Javascript bundles by default. We can use the
ExtractTextPlugin to extracts them into external .css files in a
production environment.
10) Unit tests
karma
mocha
karma-mocha
puppeteer
karma-chrome-launcher
chai // Required by `karma-sinon-chai`.
sinon // Required by `karma-sinon-chai`.
sinon-chai // Required by `karma-sinon-chai`.
karma-sinon-chai
karma-webpack
npm install --save-dev karma mocha karma-mocha karma-chrome-launcher chai sinon sinon-chai karma-sinon-chai karma-webpack
Karma is a JavaScript command line tool that can be used to spawn a web server which loads application's source code, executes tests and reports the results. It runs on Node.js and is available as an NPM package.
Mocha is the test framework that we write test specs
with. karma-mocha lets Karma use Mocha as the test framework.
karma-chrome-launcher lets Karma run tests with Headless Chrome. Puppeteer is a Node library which provides a high-level API to control headless Chrome or Chromium over the DevTools Protocol.
Chai and Sinon
(Sinon-Chai) are integrated using
karma-sinon-chai, so all Chai
interfaces (should, expect, assert) and sinon are globally available
in test files. Just let .eslintrc know about them.
karma-webpack uses Webpack to
preprocess files in Karma.
- Cheatsheets: mocha chai sinon sinon-chai
- The Ultimate Unit Testing Cheat-sheet
TODO: reporters and coverage.
11) Using rollup for packaging
rollup
buble
rollup-plugin-buble
rollup-plugin-commonjs
uglify-js
npm install --save-dev rollup buble rollup-plugin-buble rollup-plugin-commonjs
Using Rollup for packaging seems fast.
Rollup plugins change the behaviour of Rollup at key points in the bundling process.