Introduce addons-frontend-blog-utils library (#10299)
This commit is contained in:
Родитель
e6ad7e55fa
Коммит
999c33fa6a
|
@ -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:
|
||||
|
|
10
README.md
10
README.md
|
@ -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');
|
||||
},
|
||||
);
|
11
package.json
11
package.json
|
@ -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": {
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
}),
|
||||
];
|
Загрузка…
Ссылка в новой задаче