Introduce addons-frontend-blog-utils library (#10299)

This commit is contained in:
William Durand 2021-04-07 22:00:14 +02:00 коммит произвёл GitHub
Родитель e6ad7e55fa
Коммит 999c33fa6a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 218 добавлений и 0 удалений

Просмотреть файл

@ -65,6 +65,15 @@ jobs:
- *save_build_cache
- run: yarn build-ci
build-blog-utils:
<<: *defaults
steps:
- checkout
- *restore_build_cache
- *run_yarn_install
- *save_build_cache
- run: yarn build:blog-utils-prod
test:
<<: *defaults
steps:
@ -244,6 +253,7 @@ workflows:
- test-next
- check
- dennis-lint
- build-blog-utils
- release-tag:
filters:
tags:

Просмотреть файл

@ -341,6 +341,15 @@ curl https://addons-dev.allizom.org/__version__
:bulb: You can install the [amo-info extension](https://addons.mozilla.org/en-US/firefox/addon/amo-info/) to easily view this information.
## Addons Frontend Blog Utils
This project also contains code to build a library named `addons-frontend-blog-utils` and offers the following commands:
- `yarn build:blog-utils-dev`: build the library and start a watcher to rebuild the library on change
- `yarn build:blog-utils-prod`: build the library in production mode
This library is exclusively designed to work with [addons-blog][].
## Core technologies
- Based on Redux + React
@ -351,3 +360,4 @@ curl https://addons-dev.allizom.org/__version__
[bundlesize]: https://github.com/siddharthkp/bundlesize
[jest]: https://jestjs.io/docs/en/getting-started.html
[prettier]: https://prettier.io/
[addons-blog]: https://github.com/mozilla/addons-blog

Просмотреть файл

@ -0,0 +1,41 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const rootDir = path.join(__dirname, '..');
const distDir = path.join(rootDir, 'dist');
const nodeModulesDir = path.join(rootDir, 'node_modules');
const mainPackageJson = require(path.join(rootDir, 'package.json'));
const isomorphicFetchPackageJson = require(path.join(
nodeModulesDir,
'isomorphic-fetch',
'package.json',
));
const packageJsonForBlogUtils = `{
"name": "addons-frontend-blog-utils",
"version": "${mainPackageJson.version}",
"main": "node.js",
"browser": "web.js",
"style": "style.css",
"dependencies": {
"jsdom": "${mainPackageJson.dependencies.jsdom}",
"node-fetch": "${isomorphicFetchPackageJson.dependencies['node-fetch']}"
}
}
`;
fs.writeFile(
path.join(distDir, 'package.json'),
packageJsonForBlogUtils,
'utf-8',
(err) => {
if (err) {
console.error(err);
return;
}
console.log('done');
},
);

Просмотреть файл

@ -9,6 +9,9 @@
},
"scripts": {
"build": "npm run clean && better-npm-run build",
"build:blog-utils": "npm run clean && bin/create-package-json-for-blog-utils && better-npm-run build:blog-utils",
"build:blog-utils-dev": "NODE_ENV=development npm run build:blog-utils -- --watch",
"build:blog-utils-prod": "NODE_ENV=production npm run build:blog-utils",
"build-check": "bin/build-checks.js",
"build-ci": "npm run build && npm run bundlesize",
"build-locales": "bin/build-locales",
@ -47,6 +50,14 @@
"NODE_PATH": "./:./src"
}
},
"build:blog-utils": {
"command": "webpack --config webpack.blog-utils.config.babel.js",
"env": {
"NODE_ICU_DATA": "./node_modules/full-icu",
"NODE_PATH": "./:./src",
"NODE_CONFIG_ENV": "prod"
}
},
"amo:olympia": {
"command": "better-npm-run start-dev-proxy",
"env": {

48
src/blog-utils/index.js Normal file
Просмотреть файл

@ -0,0 +1,48 @@
/* @flow */
import * as React from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'connected-react-router';
import { createMemoryHistory } from 'history';
import I18nProvider from 'amo/i18n/Provider';
import { makeI18n } from 'amo/i18n/utils';
import { setClientApp, setLang } from 'amo/reducers/api';
import createStore from 'amo/store';
import Footer from 'amo/components/Footer';
import './styles.scss';
type RenderParams = {|
app: string,
lang: string,
component: React.Node,
|};
const render = ({ app, lang, component }: RenderParams) => {
// The first argument should be of type I18nConfig but we can pass an empty
// object here because it's fine for en-US content.
// $FlowIgnore: see comment above
const i18n = makeI18n({}, lang);
const { store } = createStore();
store.dispatch(setClientApp(app));
store.dispatch(setLang(lang));
return renderToStaticMarkup(
<I18nProvider i18n={i18n}>
<Provider store={store}>
<ConnectedRouter history={createMemoryHistory()}>
{component}
</ConnectedRouter>
</Provider>
</I18nProvider>,
);
};
export const buildFooter = (): string => {
const app = 'firefox';
const lang = 'en-US';
return render({ app, lang, component: <Footer noLangPicker /> });
};

Просмотреть файл

@ -0,0 +1 @@
@import '~amo/css/styles';

Просмотреть файл

@ -0,0 +1,8 @@
// This is a no-op tracking implementation.
export default {
sendEvent() {},
pageView() {},
settPage() {},
setDimension() {},
sendWebVitalStats() {},
};

Просмотреть файл

@ -0,0 +1,14 @@
import cheerio from 'cheerio';
import { buildFooter } from 'blog-utils';
describe(__filename, () => {
describe('buildFooter', () => {
it('returns the footer HTML', () => {
const html = cheerio.load(buildFooter());
expect(html('.Footer')).toHaveLength(1);
expect(html('.Footer-language-picker')).toHaveLength(0);
});
});
});

Просмотреть файл

@ -0,0 +1,75 @@
/* eslint-disable max-len, import/no-extraneous-dependencies */
import path from 'path';
import webpack from 'webpack';
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import TerserPlugin from 'terser-webpack-plugin';
import { getPlugins, getRules } from './webpack-common';
const makeConfig = ({ target, externals = {} }) => ({
mode: process.env.NODE_ENV,
devtool: false,
entry: {
'index': 'blog-utils',
},
output: {
filename: `${target}.js`,
library: {
name: 'AddonsFrontendBlogUtils',
type: 'umd',
},
globalObject: 'this',
},
target,
externals,
module: {
// Set a file limit to embed assets in CSS. It's needed to make this
// library easier to use in addons-blog.
rules: getRules({ fileLimit: 20000 }),
},
plugins: [
...getPlugins({ withBrowserWindow: target === 'web' }),
new webpack.NormalModuleReplacementPlugin(
/amo\/tracking/,
'blog-utils/tracking.js',
),
new MiniCssExtractPlugin({ filename: 'style.css' }),
],
resolve: {
modules: [path.resolve(__dirname, 'src'), 'node_modules'],
},
optimization: {
minimizer: [
new TerserPlugin({
extractComments: false,
sourceMap: false,
terserOptions: {
output: {
comments: false,
},
compress: {
drop_console: true,
},
},
}),
new CssMinimizerPlugin(),
],
},
});
// This creates a webpack multi-config to generate two JS bundles (node and
// browser). The `target` value is used as filename.
export default [
makeConfig({ target: 'web' }),
makeConfig({
target: 'node',
externals: {
// Those dependencies are declared in the `package.json` file of this
// library.
jsdom: 'jsdom',
'node-fetch': 'commonjs2 node-fetch',
},
}),
];