Update branch

Merge branch 'master' of github.com:strapi/strapi into add-overlay-blocker
This commit is contained in:
cyril lopez 2018-01-17 11:23:33 +01:00
commit aa06c0bfd0
28 changed files with 407 additions and 232 deletions

View File

@ -6,7 +6,7 @@ git:
language: node_js
node_js:
- "8"
- "9"
before_install:
- export CHROME_BIN=chromium-browser

View File

@ -111,51 +111,73 @@ This will replace the folder's content located at `./admin/admin/build`. Visit h
## Deployment
There is three cases to deploy the administration panel:
1. On the same server as the API.
2. Without the plugins on another server (AWS S3, Azure, etc) as the API.
3. With the plugins on different servers as the API.
The administration is nothing more than a React front-end application calling an API. The front-end and the back-end are independent and can be deployed on different servers which brings us to different scenarios:
Let's dive into the build configurations. The file should look like this:
1. Deploy the entire project on the same server.
2. Deploy the administration panel on another server (AWS S3, Azure, etc) than the API.
3. Deploy the administration panel and the plugins on another server than the API.
Let's dive into the build configurations for each case.
#### Deploy the entire project on the same server.
You don't need to touch anything in your configuration file. This is the default behaviour and the build configurations will be automatically set. The server will start on the defined port and the administration panel will be accessible through http://yourdomain.com:1337/dashboard.
You might want to change the path to access to the administration panel. Here the required configurations to change the path:
**Path —** `./config/environment/**/server.json`.
```json
```js
{
"host": "localhost",
"port": 1337,
"autoReload": {
"enabled": false
},
"cron": {
"enabled": false
},
"admin": {
"path": "/dashboard" // We change the path to access to the admin (highly recommended for security reasons).
}
}
```
**You have to rebuild the administration panel to make this work.** Please follow the [step #2 of the deployment guide](../guides/deployment.md).
#### Deploy the administration panel on another server (AWS S3, Azure, etc) than the API.
It's very common to deploy the front-end and the back-end on different servers. Here the required configurations to handle this case:
**Path —** `./config/environment/**/server.json`.
```js
{
"host": "localhost",
"port": 1337,
"autoReload": {
"enabled": false
},
"cron": {
"enabled": false
},
"admin": {
"path": "/dashboard",
"build": {
"host": "https://admin.myapp.com",
"backend": "https://api.myapp.com:8080",
"host": "/", // Note: The administration will be accessible from the root of the domain (ex: http//yourfrontend.com/)
"backend": "http://yourbackend.com",
"plugins": {
"source": "host",
"folder": "/plugins"
"source": "backend" // What does it means? The script tags in the index.html will use the backend value to load the plugins (ex: http://yourbackend.com/dashboard/content-manager/main.js).
}
}
}
}
```
#### On the same server as the API
The administration URL will be http://yourfrontend.com and every request from the panel will hit the backend at http://yourbackend.com. The plugins will be injected through the `origin` (means the API itself). In other words, the plugins URLs will be `http://yourbackend.com/dashboard/content-manager/main.js`.
You don't need to touch anything in your configuration file. This is the default behaviour and the build configurations will be automatically set.
> Note: How it is possible? The API (the Strapi server) owns the plugin and these plugins are exposed through `http://yourbackend.com/admin/**/main.js`
#### Without the plugins on another server
**Path —** `./config/environment/**/server.json`.
```json
{
"admin": {
"build": {
"host": "https://admin.myapp.com",
"backend": "https://api.myapp.com:8080",
"plugins": {
"source": "origin"
}
}
}
}
```
The administration URL will be https://admin.myapp.com and every request from the panel will hit the backend at https://api.myapp.com:8080. The plugins will be injected through the `origin` (means the API itself). In other words, the plugins URLs will be `https://api.myapp.com:8080/admin/content-manager/main.js`.
The DOM should look like this:
**Path —** `./admin/admin/build/index.html`.
```html
@ -163,38 +185,46 @@ The administration URL will be https://admin.myapp.com and every request from th
<head></head>
<body>
<div id="app"></div>
<script type="text/javascript" src="https://admin.myapp.com/admin/vendor.dll.js"></script>
<script type="text/javascript" src="https://admin.myapp.com/admin/main.js"></script>
<script src="https://api.myapp.com:8080/admin/content-manager/main.js"></script>
<script src="https://api.myapp.com:8080/admin/settings-manager/main.js"></script>
<script src="https://api.myapp.com:8080/admin/content-type-builder/main.js"></script>
<script type="text/javascript" src="/vendor.dll.js"></script>
<script type="text/javascript" src="/main.js"></script>
<script src="http://yourbackend.com/dashboard/content-manager/main.js"></script>
<script src="http://yourbackend.com/dashboard/settings-manager/main.js"></script>
<script src="http://yourbackend.com/dashboard/content-type-builder/main.js"></script>
</body>
</html>
```
> Note: The plugins are injected using the `./admin/admin/build/config/plugins.json`. To see the plugins URLs in the `index.html`, you need to launch the administration panel in the browser.
#### With the plugins on another server
#### Deploy the administration panel and the plugins on another server than the API
In this case, we suppose that you decided to put your administration and the plugins on the same server but on a different server as the API.
**Path —** `./config/environment/**/server.json`.
```json
```js
{
"host": "localhost",
"port": 1337,
"autoReload": {
"enabled": false
},
"cron": {
"enabled": false
},
"admin": {
"build": {
"host": "https://admin.myapp.com",
"backend": "https://api.myapp.com:8080",
"host": "http://yourfrontend.com/dashboard", // Note: The custom path has moved directly in the host URL.
"backend": "http://yourbackend.com",
"plugins": {
"source": "host",
"folder": "plugins"
"source": "host", // What does it means? The script tags in the index.html will use the host value to load the plugins (ex: http://yourfrontend.com/dashboard/plugins/content-manager/main.js).
"folder": "/plugins"
}
}
}
}
```
The administration URL will be https://admin.myapp.com and every request from the panel will hit the backend at https://api.myapp.com:8080. The plugins will be injected through the `host`. It means that the plugins URLs will use the host URL as the origin. So the plugins URLs will be `https://admin.myapp.com/plugins/content-manager/main.js`.
The administration URL will be http://yourfrontend.com/dashboard and every request from the panel will hit the backend at http://yourbackend.com. The plugins will be injected through the `host`. It means that the plugins URLs will use the host URL as the origin. So the plugins URLs will be `http://yourfrontend.com/dashboard/plugins/content-manager/main.js`.
We also added a `folder` setting to separate the plugins from the administration build. In your server, the files structure should look like this:
```
@ -233,11 +263,11 @@ The generated `index.html` will look like this:
<head></head>
<body>
<div id="app"></div>
<script type="text/javascript" src="https://admin.myapp.com/admin/vendor.dll.js"></script>
<script type="text/javascript" src="https://admin.myapp.com/admin/main.js"></script>
<script src="https://admin.myapp.com/plugins/content-manager/main.js"></script>
<script src="https://admin.myapp.com/plugins/settings-manager/main.js"></script>
<script src="https://admin.myapp.com/plugins/content-type-builder/main.js"></script>
<script type="text/javascript" src="/dashboard/vendor.dll.js"></script>
<script type="text/javascript" src="/dashboard/main.js"></script>
<script src="/dashboard/plugins/content-manager/main.js"></script>
<script src="/dashboard/plugins/settings-manager/main.js"></script>
<script src="/dashboard/plugins/content-type-builder/main.js"></script>
</body>
</html>
```

View File

@ -1,4 +1,4 @@
# Authentification
# Authentication
## Register a new user.
@ -53,7 +53,7 @@ $.ajax({
});
```
## Use your token to be identify as user.
## Use your token to be identified as a user.
By default, each API request is identified as `guest` role (see permissions of `guest`'s role in your admin dashboard). To make a request as a user, you have to set the `Authorization` token in your request headers. You receive a 401 error if you are not authorized to make this request or if your authorization header is not correct.

View File

@ -13,23 +13,23 @@ Update the `production` settings with the IP and domain name where the project w
"enabled": false
},
"admin": {
"build": {
"path": "/dashboard" // We highly recommend to change the default `/admin` path for security reasons.
}
"path": "/dashboard" // We highly recommend to change the default `/admin` path for security reasons.
}
}
```
#### #2 - Setup
**⚠️ If you changed the path to access to the administration, the step #2 is required.**
Run this following command to install the dependencies and build the project.
#### #2 - Setup (optional)
Run this following command to install the dependencies and build the project with your custom configurations.
```bash
cd /path/to/the/project
npm run setup
```
> Note: The `build` folders are ignored (.gitignore). If you're cloning your git repository on your server, you need to run this command on your server.
> Note: To display the build logs use the --debug option `npm run setup --debug`.
#### #3 - Launch the server
@ -43,4 +43,4 @@ NODE_ENV=production npm start
### Advanced configurations
If you want to host the administration on another server than the API, [please take a look at this dedicated section](advanced/customize-admin.md#deployment).
If you want to host the administration on another server than the API, [please take a look at this dedicated section](../advanced/customize-admin.md#deployment).

View File

@ -6,18 +6,6 @@
*/
/* eslint-disable */
// Retrieve remote and backend URLs.
const remoteURL = window.location.port === '4000' ? 'http://localhost:4000/admin' : process.env.REMOTE_URL || 'http://localhost:1337/admin';
const backendURL = process.env.BACKEND_URL || 'http://localhost:1337';
// Retrieve development URL to avoid to re-build.
const $body = document.getElementsByTagName('body')[0];
const devFrontURL = $body.getAttribute('front');
const devBackendURL = $body.getAttribute('back');
$body.removeAttribute('front');
$body.removeAttribute('back');
import './public-path';
import 'babel-polyfill';
@ -51,11 +39,11 @@ const plugins = (() => {
/* eslint-enable */
// Create redux store with history
const initialState = {};
const basename = strapi.remoteURL.replace(window.location.origin, '');
const history = createHistory({
basename: (devFrontURL || remoteURL).replace(window.location.origin, ''),
basename,
});
const store = configureStore(initialState, history);
const store = configureStore({}, history);
const render = (translatedMessages) => {
ReactDOM.render(
@ -94,7 +82,7 @@ window.onload = function onLoad() {
// Don't inject plugins in development mode.
if (window.location.port !== '4000') {
fetch(`${devFrontURL || remoteURL}/config/plugins.json`)
fetch(`${strapi.remoteURL}/config/plugins.json`)
.then(response => {
return response.json();
})
@ -103,12 +91,14 @@ if (window.location.port !== '4000') {
store.dispatch(unsetHasUserPlugin());
}
const $body = document.getElementsByTagName('body')[0];
(plugins || []).forEach(plugin => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.onerror = function (oError) {
const source = new URL(oError.target.src);
const url = new URL(`${devFrontURL || remoteURL}`);
const url = new URL(`${strapi.remoteURL}`);
if (!source || !url) {
throw new Error(`Impossible to load: ${oError.target.src}`);
@ -124,7 +114,10 @@ if (window.location.port !== '4000') {
$body.appendChild(newScript);
};
script.src = plugin.source[process.env.NODE_ENV];
script.src = plugin.source[process.env.NODE_ENV].indexOf('://') === -1 ?
`${basename}${plugin.source[process.env.NODE_ENV]}`.replace('//', '/'): // relative
plugin.source[process.env.NODE_ENV]; // absolute
$body.appendChild(script);
});
})
@ -188,8 +181,7 @@ const displayNotification = (message, status) => {
*/
window.strapi = Object.assign(window.strapi || {}, {
remoteURL: devFrontURL || remoteURL,
backendURL: devBackendURL || backendURL,
mode: process.env.MODE || 'host',
registerPlugin,
notification: {
success: (message) => {

View File

@ -63,8 +63,8 @@ class PluginCard extends React.Component {
}
}
handleDownloadPlugin = () => {
this.props.downloadPlugin();
handleDownloadPlugin = (e) => {
this.props.downloadPlugin(e);
}
shouldOpenModal = (props) => {

View File

@ -34,11 +34,15 @@ export function* pluginDownload() {
const response = yield call(request, '/admin/plugins/install', opts, true);
if (response.ok) {
yield put(downloadPluginSucceeded());
setTimeout(() => {
window.location.reload();
}, 500);
yield new Promise(resolve => {
setTimeout(() => {
resolve();
}, 8000);
});
yield put(downloadPluginSucceeded());
window.location.reload();
}
} catch(err) {
yield put(downloadPluginError());

View File

@ -1,5 +1,29 @@
// Retrieve URLs.
const remoteURL = window.location.port === '4000' ? 'http://localhost:4000/admin' : process.env.REMOTE_URL || 'http://localhost:1337/admin';
const devURL = document.getElementsByTagName('body')[0].getAttribute('front');
// Retrieve remote and backend URLs.
const remoteURL = (() => {
if (window.location.port === '4000') {
return 'http://localhost:4000/admin';
}
__webpack_public_path__ = window.location.port === '4000' ? `${window.location.origin}/` : `${(devURL || remoteURL).replace(window.location.origin, '')}/`;
// Relative URL (ex: /dashboard)
if (process.env.REMOTE_URL[0] === '/') {
return (window.location.origin + process.env.REMOTE_URL).replace(/\/$/, '');
}
return process.env.REMOTE_URL.replace(/\/$/, '');
})();
const backendURL = (process.env.BACKEND_URL === '/' ? window.location.origin : process.env.BACKEND_URL);
// Retrieve development URL to avoid to re-build.
const $body = document.getElementsByTagName('body')[0];
const devFrontURL = $body.getAttribute('front') ? window.location.origin + $body.getAttribute('front').replace(/\/$/, '') : null;
const devBackendURL = $body.getAttribute('back') ? window.location.origin + $body.getAttribute('back').replace(/\/$/, '') : null;
$body.removeAttribute('front');
$body.removeAttribute('back');
window.strapi = {
remoteURL: devFrontURL || remoteURL,
backendURL: devBackendURL || backendURL,
};
__webpack_public_path__ = window.location.port === '4000' ? `${window.location.origin}/` : `${(strapi.remoteURL).replace(window.location.origin, '')}/`;

View File

@ -11,8 +11,8 @@
"preanalyze": "npm run analyze:clean",
"analyze": "node ./node_modules/strapi-helper-plugin/lib/internals/scripts/analyze.js",
"build:dev": "npm run build:dll && node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development IS_ADMIN=true node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config ./node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
"build": "npm run build:dll && node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production IS_ADMIN=true node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config ./node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
"build:dll": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production IS_ADMIN=true node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config ./node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.dll.babel.js --color -p --progress",
"build": "APP_PATH=$APP_PATH npm run build:dll && node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production IS_ADMIN=true node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config ./node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
"build:dll": "APP_PATH=$APP_PATH node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production IS_ADMIN=true node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config ./node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.dll.babel.js --color -p --progress",
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development PORT=4000 IS_ADMIN=true node ./node_modules/strapi-helper-plugin/lib/server",
"generate": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/plop --plopfile ./node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
@ -21,11 +21,13 @@
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented.",
"prepublishOnly": "npm run build",
"setup": "npm install && node ./scripts/setup.js"
"setup": "node ./scripts/setup.js"
},
"dependencies": {
"shelljs": "^0.7.8"
},
"devDependencies": {
"sanitize.css": "^4.1.0",
"shelljs": "^0.7.8",
"strapi-helper-plugin": "3.0.0-alpha.7.3",
"strapi-utils": "3.0.0-alpha.7.3"
},
@ -46,4 +48,4 @@
"npm": ">= 3.0.0"
},
"license": "MIT"
}
}

View File

@ -4,45 +4,78 @@ const _ = require('lodash');
shell.echo('');
shell.echo('🕓 The setup process can take few minutes.');
shell.echo('📦 Installing admin packages...');
shell.echo('');
shell.echo(`🔸 Administration Panel`);
shell.echo('📦 Installing packages...');
const pwd = shell.pwd();
shell.exec(`cd ${path.resolve(pwd.stdout, 'node_modules', 'strapi-helper-plugin')} && npm install`, {
silent: true
const silent = process.env.npm_config_debug !== 'true';
const isDevelopmentMode = path.resolve(pwd.stdout).indexOf('strapi-admin') !== -1;
const appPath = isDevelopmentMode ? path.resolve(process.env.PWD, '..') : path.resolve(pwd.stdout, '..');
// Remove package-lock.json.
shell.rm('-rf', path.resolve(appPath, 'package-lock.json'));
shell.rm('-rf', path.resolve(appPath, 'admin', 'package-lock.json'));
// Install the project dependencies.
shell.exec(`cd ${appPath} && npm install --ignore-scripts`, {
silent
});
// Install the administration dependencies.
shell.exec(`cd ${path.resolve(appPath, 'admin')} && npm install`, {
silent
});
if (isDevelopmentMode) {
shell.exec(`cd ${path.resolve(appPath, 'admin')} && npm link strapi-helper-plugin && npm link strapi-utils`, {
silent
});
} else {
shell.exec(`cd ${path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin')} && npm install`, {
silent
});
}
shell.echo('🏗 Building...');
const build = shell.exec(`cd ${path.resolve(pwd.stdout)} && npm run build`, {
silent: true
const build = shell.exec(`cd ${path.resolve(appPath, 'admin')} && APP_PATH=${appPath} npm run build`, {
silent
});
if (build.stderr) {
if (build.stderr && build.code !== 0) {
console.error(build.stderr);
process.exit(1);
}
const plugins = path.resolve(pwd.stdout, '..', 'plugins');
shell.echo('✅ Success');
shell.echo('');
shell.ls('* -d', plugins).forEach(function (plugin) {
shell.echo(`🔸 ${_.upperFirst(plugin)} (plugin)`);
shell.echo('📦 Installing packages...');
shell.exec(`cd ${path.resolve(plugins, plugin)} && npm install`, {
silent: true
if (process.env.npm_config_plugins === 'true') {
const plugins = path.resolve(appPath, 'plugins');
shell.ls('* -d', plugins).forEach(function (plugin) {
shell.echo(`🔸 Plugin - ${_.upperFirst(plugin)}`);
shell.echo('📦 Installing packages...');
shell.exec(`cd ${path.resolve(plugins, plugin)} && npm install`, {
silent
});
shell.exec(`cd ${path.resolve(plugins, plugin, 'node_modules', 'strapi-helper-plugin')} && npm install`, {
silent
});
shell.echo('🏗 Building...');
const build = shell.exec(`cd ${path.resolve(plugins, plugin)} && APP_PATH=${appPath} npm run build`, {
silent
});
if (build.stderr && build.code !== 0) {
console.error(build.stderr);
process.exit(1);
}
shell.echo('✅ Success');
shell.echo('');
});
shell.exec(`cd ${path.resolve(plugins, plugin, 'node_modules', 'strapi-helper-plugin')} && npm install`, {
silent: true
});
shell.echo('🏗 Building...');
const build = shell.exec(`cd ${path.resolve(plugins, plugin)} && npm run build`, {
silent: true
});
if (build.stderr) {
console.error(build.stderr);
}
shell.echo('');
});
}

View File

@ -5,9 +5,9 @@
"connector": "strapi-mongoose",
"settings": {
"client": "mongo",
"host": "localhost",
"port": 27017,
"database": "production",
"host": "${process.env.DATABASE_HOST || 'localhost'}",
"port": "${process.env.DATABASE_PORT || 27017}",
"database": "${process.env.DATABASE_NAME || 'production'}",
"username": "",
"password": ""
},

View File

@ -24,7 +24,7 @@ module.exports = scope => {
'description': 'A Strapi application.',
'main': './server.js',
'scripts': {
'setup': 'npm install --ignore-scripts && cd admin && npm run setup', // Ready to deploy setup
'setup': 'cd admin && npm run setup', // Ready to deploy setup
'start': 'node server.js',
'strapi': 'node_modules/strapi/bin/strapi.js', // Allow to use `npm run strapi` CLI,
'lint': 'node_modules/.bin/eslint api/**/*.js config/**/*.js plugins/**/*.js',

View File

@ -91,7 +91,6 @@ lcov.info
pids
logs
results
build
node_modules
.node_history

File diff suppressed because one or more lines are too long

View File

@ -11,8 +11,21 @@ const pkg = require(path.resolve(process.cwd(), 'package.json'));
const pluginId = pkg.name.replace(/^strapi-/i, '');
const isAdmin = process.env.IS_ADMIN === 'true';
const appPath = isAdmin ? path.resolve(process.env.PWD, '..') : path.resolve(process.env.PWD, '..', '..');
const appPath = (() => {
if (process.env.APP_PATH) {
return process.env.APP_PATH;
}
return isAdmin ? path.resolve(process.env.PWD, '..') : path.resolve(process.env.PWD, '..', '..');
})();
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
const adminPath = (() => {
if (isSetup) {
return isAdmin ? path.resolve(appPath, 'strapi-admin') : path.resolve(process.env.PWD);
}
return path.resolve(appPath, 'admin');
})();
if (!isSetup) {
try {
@ -23,7 +36,9 @@ if (!isSetup) {
strapi.log.level = 'silent';
(async () => {
await strapi.load();
await strapi.load({
environment: process.env.NODE_ENV
});
})();
} catch (e) {
console.log(e);
@ -33,8 +48,10 @@ if (!isSetup) {
// Define remote and backend URLs.
const URLs = {
host: null,
backend: null
host: '/admin',
backend: '/',
publicPath: null,
mode: 'host'
};
if (isAdmin && !isSetup) {
@ -43,11 +60,20 @@ if (isAdmin && !isSetup) {
try {
const server = require(serverConfig);
const path = _.get(server, 'admin.path', '/admin');
if (process.env.PWD.indexOf('/admin') !== -1) {
URLs.host = _.get(server, 'admin.build.host', `http://${_.get(server, 'host', 'localhost')}:${_.get(server, 'port', 1337)}${path}`);
URLs.backend = _.get(server, 'admin.build.backend', `http://${_.get(server, 'host', 'localhost')}:${_.get(server, 'port', 1337)}`);
if (_.get(server, 'admin.build.host')) {
URLs.host = _.get(server, 'admin.build.host', '/admin').replace(/\/$/, '') || '/';
} else {
URLs.host = _.get(server, 'admin.path', '/admin');
}
URLs.publicPath = URLs.host;
URLs.backend = _.get(server, 'admin.build.backend', `/`);
if (_.get(server, 'admin.build.plugins.source') === 'backend') {
URLs.mode = 'backend';
}
}
} catch (e) {
throw new Error(`Impossible to access to ${serverConfig}`)
@ -83,7 +109,7 @@ if (process.env.npm_lifecycle_event === 'start') {
module.exports = (options) => ({
entry: options.entry,
output: Object.assign({ // Compile into js/build.js
path: path.join(process.env.PWD, 'admin', 'build')
path: path.join(adminPath, 'admin', 'build')
}, options.output), // Merge with env dependent settings
module: {
loaders: [{
@ -111,13 +137,13 @@ module.exports = (options) => ({
},
},
},
include: [path.join(process.env.PWD, 'admin', 'src')]
include: [path.join(adminPath, 'admin', 'src')]
.concat(plugins.src.reduce((acc, current) => {
acc.push(path.resolve(appPath, 'plugins', current, 'admin', 'src'), plugins.folders[current]);
return acc;
}, []))
.concat([path.join(process.env.PWD, 'node_modules', 'strapi-helper-plugin', 'lib', 'src')])
.concat([path.join(adminPath, 'node_modules', 'strapi-helper-plugin', 'lib', 'src')])
}, {
// Transform our own .scss files
test: /\.scss$/,
@ -205,6 +231,7 @@ module.exports = (options) => ({
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
REMOTE_URL: JSON.stringify(URLs.host),
BACKEND_URL: JSON.stringify(URLs.backend),
MODE: JSON.stringify(URLs.mode), // Allow us to define the public path for the plugins assets.
},
}),
new webpack.NamedModulesPlugin()

View File

@ -15,7 +15,13 @@ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPl
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const isAdmin = process.env.IS_ADMIN === 'true';
const appPath = isAdmin ? path.resolve(process.env.PWD, '..') : path.resolve(process.env.PWD, '..', '..');
const appPath = (() => {
if (process.env.APP_PATH) {
return process.env.APP_PATH;
}
return isAdmin ? path.resolve(process.env.PWD, '..') : path.resolve(process.env.PWD, '..', '..');
})();
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
// Load plugins into the same build in development mode.

View File

@ -12,7 +12,13 @@ const path = require('path');
const webpack = require('webpack');
const isAdmin = process.env.IS_ADMIN === 'true';
const appPath = isAdmin ? path.resolve(process.env.PWD, '..') : path.resolve(process.env.PWD, '..', '..');
const appPath = (() => {
if (process.env.APP_PATH) {
return process.env.APP_PATH;
}
return isAdmin ? path.resolve(process.env.PWD, '..') : path.resolve(process.env.PWD, '..', '..');
})();
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
module.exports = {

View File

@ -2,6 +2,8 @@
const _ = require('lodash');
const path = require('path');
const base = require('./webpack.base.babel');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const cssnext = require('postcss-cssnext');
@ -10,7 +12,7 @@ const postcssReporter = require('postcss-reporter');
const webpack = require('webpack');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
const WriteJsonPlugin = require('write-json-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const pkg = require(path.resolve(process.cwd(), 'package.json'));
const pluginId = pkg.name.replace(/^strapi-plugin-/i, '');
@ -18,15 +20,19 @@ const dllPlugin = pkg.dllPlugin;
const isAdmin = process.env.IS_ADMIN === 'true';
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
const appPath = isAdmin ? path.resolve(process.env.PWD, '..') : path.resolve(process.env.PWD, '..', '..');
// Necessary configuration file to ensure that plugins will be loaded.
const pluginsToInitialize = (() => {
try {
return require(path.resolve(appPath, 'admin', 'src', 'config', 'plugins.json'));
} catch (e) {
return [];
const appPath = (() => {
if (process.env.APP_PATH) {
return process.env.APP_PATH;
}
return isAdmin ? path.resolve(process.env.PWD, '..') : path.resolve(process.env.PWD, '..', '..');
})();
const adminPath = (() => {
if (isSetup) {
return isAdmin ? path.resolve(appPath, 'strapi-admin') : path.resolve(process.env.PWD, '..');
}
return path.resolve(appPath, 'admin');
})();
const plugins = [
@ -54,25 +60,32 @@ const plugins = [
// new BundleAnalyzerPlugin(),
];
// Default configurations.
const settings = {
path: 'admin',
folder: 'plugins',
host: 'http://localhost:1337'
};
let publicPath;
if (!isSetup) {
// Load server configurations.
if (isAdmin && !isSetup) {
// Load server configuration.
const serverConfig = path.resolve(appPath, 'config', 'environments', _.lowerCase(process.env.NODE_ENV), 'server.json');
const server = require(serverConfig);
const pathAccess = _.get(server, 'admin.path', 'admin');
try {
const server = require(serverConfig);
Object.assign(settings, {
path: pathAccess[0] === '/' ? pathAccess.substring(1) : pathAccess,
folder: _.get(server, 'admin.build.plugins.folder', 'plugins'),
host: _.get(server, 'admin.build.host', 'http://localhost:1337')
});
if (process.env.PWD.indexOf('/admin') !== -1) {
if (_.get(server, 'admin.build.host')) {
publicPath = _.get(server, 'admin.build.host', '/admin').replace(/\/$/, '') || '/';
} else {
publicPath = _.get(server, 'admin.path', '/admin');
}
}
} catch (e) {
throw new Error(`Impossible to access to ${serverConfig}`);
}
// Note: Travis failed with it.
plugins.push(new CopyWebpackPlugin([{
from: 'config/plugins.json',
context: path.resolve(adminPath, 'admin', 'src'),
to: 'config/plugins.json'
}]));
}
// Build the `index.html file`
@ -99,12 +112,6 @@ if (isAdmin) {
plugins.push(new AddAssetHtmlPlugin({
filepath: path.resolve(__dirname, 'dist/*.dll.js')
}));
plugins.push(new WriteJsonPlugin({
object: pluginsToInitialize,
path: 'config',
// default output is timestamp.json
filename: 'plugins.json',
}));
}
const main = (() => {
@ -117,17 +124,18 @@ const main = (() => {
return path.join(process.env.PWD, 'node_modules', 'strapi-helper-plugin', 'lib', 'src', 'app.js');
})();
module.exports = require('./webpack.base.babel')({
module.exports = base({
// In production, we skip all hot-reloading stuff
entry: {
main
},
// Utilize long-term caching by adding content hashes (not compilation hashes) to compiled assets
output: {
output: _.omitBy({
filename: '[name].js',
chunkFilename: '[name].[chunkhash].chunk.js'
},
chunkFilename: '[name].[chunkhash].chunk.js',
publicPath,
}, _.isUndefined),
// In production, we minify our CSS with cssnano
postcssPlugins: [

View File

@ -2,4 +2,12 @@ const pluginPkg = require('../../../../package.json');
const pluginId = pluginPkg.name.replace(/^strapi-plugin-/i, '');
const publicPath = `plugins/${pluginId}/`;
__webpack_public_path__ = window.location.port === '4000' ? `${window.location.origin}/` : `${(strapi.remoteURL).replace(window.location.origin, '')}/${publicPath}`;
__webpack_public_path__ = (() => {
if (window.location.port === '4000') {
return `${window.location.origin}/`;
} else if (strapi.mode === 'backend') {
return `${strapi.backendURL}/${publicPath}`;
}
return `${(strapi.remoteURL).replace(window.location.origin, '')}/${publicPath}`;
})();

View File

@ -46,6 +46,7 @@
"bootstrap": "^4.0.0-alpha.6",
"chalk": "^2.1.0",
"classnames": "^2.2.5",
"copy-webpack-plugin": "^4.3.1",
"cross-env": "^5.0.5",
"css-loader": "^0.28.5",
"eslint": "^4.4.1",
@ -108,7 +109,6 @@
"webpack-bundle-analyzer": "^2.9.0",
"webpack-dev-middleware": "^1.12.0",
"webpack-hot-middleware": "^2.18.2",
"whatwg-fetch": "^2.0.3",
"write-json-webpack-plugin": "^1.0.2"
"whatwg-fetch": "^2.0.3"
}
}

View File

@ -24,7 +24,7 @@ class Strapi extends EventEmitter {
constructor() {
super();
this.setMaxListeners(15);
this.setMaxListeners(100);
this.reload = this.reload();

View File

@ -4,12 +4,15 @@
const _ = require('lodash');
const path = require('path');
const fs = require('fs');
const cheerio = require('cheerio')
const cheerio = require('cheerio');
const URL = require('url');
module.exports = function() {
return new Promise((resolve, reject) => {
try {
if (this.config.environment === 'test') {
const environment = this.config.environment;
if (environment === 'test') {
return resolve();
}
@ -39,14 +42,21 @@ module.exports = function() {
$('script').each(function(i, elem) {
if ($(this).attr('src')) {
const parse = path.parse($(this).attr('src'));
const url = URL.parse(_.get(strapi.config.currentEnvironment.server, 'admin.build.host', _.get(strapi.config.currentEnvironment.server, 'admin.path', '/admin')));
$(this).attr('src', `${_.get(strapi.config.currentEnvironment.server, 'admin.path', '/admin')}/${parse.base}`);
$(this).attr('src', `${url.pathname.replace(/\/$/, '')}/${parse.base}`);
}
});
// Remove previous
$('body').attr('front', `http://${strapi.config.currentEnvironment.server.host}:${strapi.config.currentEnvironment.server.port}${_.get(strapi.config.currentEnvironment.server, 'admin.path', '/admin')}`);
$('body').attr('back', `http://${strapi.config.currentEnvironment.server.host}:${strapi.config.currentEnvironment.server.port}`);
// Remove previous and use build configurations.
if (environment === 'production') {
$('body').removeAttr('front');
$('body').removeAttr('back');
} else {
// Update attribute with the current server configurations.
$('body').attr('front', `${_.get(strapi.config.currentEnvironment.server, 'admin.path', '/admin')}`);
$('body').attr('back', `/`);
}
fs.writeFile(sourcePath, $.html(), (err) => {
if (err) {

View File

@ -364,19 +364,18 @@ const enableHookNestedDependencies = function (name, flattenHooksConfig, force =
}
};
/**
/**
* Allow dynamic config values through
* the native ES6 template string function.
*/
const regex = /\$\{[^()]*\}/g;
const templateConfigurations = function (obj) {
// Allow values which looks like such as
// an ES6 literal string without parenthesis inside (aka function call).
const regex = /\$\{[^()]*\}/g;
return Object.keys(obj).reduce((acc, key) => {
if (isPlainObject(obj[key])) {
if (isPlainObject(obj[key]) && !isString(obj[key])) {
acc[key] = templateConfigurations(obj[key]);
} else if (isString(obj[key]) && regex.test(obj[key])) {
} else if (isString(obj[key]) && obj[key].match(regex) !== null) {
acc[key] = eval('`' + obj[key] + '`');
} else {
acc[key] = obj[key];

View File

@ -9,12 +9,14 @@ module.exports = function() {
return new Promise((resolve, reject) => {
const folder = ((url = _.get(strapi.config.currentEnvironment.server, 'admin.path', 'admin')) =>
url[0] === '/' ? url.substring(1) : url
)();
)().replace(/\/$/, '') ;
const configuratePlugin = (acc, current, source, name) => {
switch (source) {
case 'host': {
if (!_.get(this.config.environments[current].server, 'admin.build.host')) {
const host = _.get(this.config.environments[current].server, 'admin.build.host').replace(/\/$/, '') || '/';
if (!host) {
throw new Error(`You can't use \`remote\` as a source without set the \`host\` configuration.`);
}
@ -23,10 +25,10 @@ module.exports = function() {
if (_.isString(folder)) {
const cleanFolder = folder[0] === '/' ? folder.substring(1) : folder;
return `${this.config.environments[current].server.admin.build.host}/${cleanFolder}/${name}/main.js`;
return `/${host}/${cleanFolder}/${name}/main.js`.replace('//', '/');
}
return `${this.config.environments[current].server.admin.build.host}/${name}/main.js`;
return `/${host}/${name}/main.js`.replace('//', '/');
}
case 'custom':
if (!_.isEmpty(_.get(this.plugins[name].config, `sources.${current}`, {}))) {
@ -34,9 +36,12 @@ module.exports = function() {
}
throw new Error(`You have to define the source URL for each environment in \`./plugins/**/config/sources.json\``);
case 'origin':
case 'backend':
const backend = _.get(this.config.environments[current], 'server.admin.build.backend', `http://${this.config.environments[current].server.host}:${this.config.environments[current].server.port}`).replace(/\/$/, '');
return `${backend}/${folder.replace(/\/$/, '')}/${name}/main.js`;
default:
return `http://${this.config.environments[current].server.host}:${this.config.environments[current].server.port}/${folder}/${name}/main.js`;
return `/${name}/main.js`;
}
};
@ -111,7 +116,7 @@ module.exports = function() {
const data = Object.keys(this.plugins).map(name => ({
id: name,
source: Object.keys(this.config.environments).reduce((acc, current) => {
const source = _.get(this.config.environments[current].server, 'admin.build.plugins.source', 'origin');
const source = _.get(this.config.environments[current].server, 'admin.build.plugins.source', 'default');
if (_.isString(source)) {
acc[current] = configuratePlugin(acc, current, source, name);

View File

@ -1,7 +1,7 @@
{
"cors": {
"enabled": false,
"origin": true,
"origin": "*",
"expose": [
"WWW-Authenticate",
"Server-Authorization"
@ -14,7 +14,8 @@
"PUT",
"PATCH",
"DELETE",
"HEAD"
"HEAD",
"OPTIONS"
],
"headers": [
"Content-Type",

View File

@ -8,7 +8,7 @@ const { after, includes, indexOf, drop, dropRight, uniq, defaultsDeep, get, set,
module.exports = async function() {
// Set if is admin destination for middleware application.
this.app.use(async (ctx, next) => {
if (ctx.request.header['origin'] === 'http://localhost:4000') {
if (ctx.request.header['origin'] === 'http://localhost:4000' || ctx.request.method === 'OPTIONS') {
ctx.request.header['x-forwarded-host'] = 'strapi';
}

View File

@ -13,7 +13,7 @@ module.exports = {
loadFile: function(url) {
try {
// Clear cache.
delete require.cache[path.resolve(this.config.appPath, url)];
delete require.cache[require.resolve(path.resolve(this.config.appPath, url))];
// Require without cache.
return require(path.resolve(this.config.appPath, url));
} catch (e) {

View File

@ -2,79 +2,100 @@ const shell = require('shelljs');
// Store installation start date.
const installationStartDate = new Date();
const watcher = (label, cmd, withSuccess = true) => {
if (label.length > 0) {
shell.echo(`📦 ${label}`);
}
const data = shell.exec(cmd, {
silent: true
});
if (data.stderr && data.code !== 0) {
console.error(data.stderr);
process.exit(1);
}
if (label.length > 0 && withSuccess) {
shell.echo('✅ Success');
shell.echo('');
}
};
shell.echo('');
shell.echo('🕓 The setup process can take few minutes.');
shell.echo('');
// Remove existing binary.
shell.rm('-f', '/usr/local/bin/strapi.js');
shell.echo('Linking Strapi CLI...');
shell.cd('packages/strapi-utils');
shell.exec('npm link');
watcher('Linking strapi-utils...', 'npm link');
shell.cd('../strapi-generate');
shell.exec('npm install ../strapi-utils');
shell.exec('npm link');
watcher('', 'npm install ../strapi-utils');
watcher('Linking strapi-generate...', 'npm link');
shell.cd('../strapi-generate-api');
shell.exec('npm link');
watcher('Linking strapi-generate-api...', 'npm link');
shell.cd('../strapi-helper-plugin');
shell.exec('npm link');
watcher('Linking strapi-helper-plugin...', 'npm link');
shell.cd('../strapi-admin');
shell.exec('npm install ../strapi-helper-plugin');
shell.exec('npm install ../strapi-utils');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
watcher('', 'npm install ../strapi-utils --no-optional');
shell.rm('-f', 'package-lock.json');
shell.exec('npm link');
shell.exec('npm run build');
watcher('Linking strapi-admin', 'npm link --no-optional', false);
watcher('Building...', 'npm run build');
shell.cd('../strapi-generate-admin');
shell.exec('npm install ../strapi-admin');
shell.exec('npm link');
watcher('', 'npm install ../strapi-admin');
watcher('Linking strapi-generate-admin...', 'npm link');
shell.cd('../strapi-generate-new');
shell.exec('npm install ../strapi-utils');
shell.exec('npm link');
watcher('', 'npm install ../strapi-utils');
watcher('Linking strapi-generate-new', 'npm link');
shell.cd('../strapi-mongoose');
shell.exec('npm install ../strapi-utils');
shell.exec('npm link');
watcher('', 'npm install ../strapi-utils');
watcher('Linking strapi-mongoose...', 'npm link');
shell.cd('../strapi');
shell.exec('npm install ../strapi-generate ../strapi-generate-admin ../strapi-generate-api ../strapi-generate-new ../strapi-generate-plugin ../strapi-generate-policy ../strapi-generate-service ../strapi-utils');
shell.exec('npm link');
watcher('', 'npm install ../strapi-generate ../strapi-generate-admin ../strapi-generate-api ../strapi-generate-new ../strapi-generate-plugin ../strapi-generate-policy ../strapi-generate-service ../strapi-utils');
watcher('Linking strapi...', 'npm link');
shell.cd('../strapi-plugin-email');
shell.exec('npm install ../strapi-helper-plugin');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
shell.rm('-f', 'package-lock.json');
shell.exec('npm link');
shell.exec('npm run build');
watcher('Linking strapi-plugin-email...', 'npm link --no-optional', false);
watcher('Building...', 'npm run build');
shell.cd('../strapi-plugin-users-permissions');
shell.exec('npm install ../strapi-helper-plugin');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
shell.rm('-f', 'package-lock.json');
shell.exec('npm link');
shell.exec('npm run build');
watcher('Linking strapi-plugin-users-permissions...', 'npm link --no-optional', false);
watcher('Building...', 'npm run build');
shell.cd('../strapi-plugin-content-manager');
shell.exec('npm install ../strapi-helper-plugin');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
shell.rm('-f', 'package-lock.json');
shell.exec('npm link');
shell.exec('npm run build');
watcher('Linking strapi-plugin-content-manager...', 'npm link --no-optional', false);
watcher('Building...', 'npm run build');
shell.cd('../strapi-plugin-settings-manager');
shell.exec('npm install ../strapi-helper-plugin');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
shell.rm('-f', 'package-lock.json');
shell.exec('npm link');
shell.exec('npm run build');
watcher('Linking strapi-plugin-settings-manager...', 'npm link --no-optional', false);
watcher('Building...', 'npm run build');
shell.cd('../strapi-plugin-content-type-builder');
shell.exec('npm install ../strapi-helper-plugin');
shell.exec('npm install ../strapi-generate');
shell.exec('npm install ../strapi-generate-api');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
watcher('', 'npm install ../strapi-generate --no-optional');
watcher('', 'npm install ../strapi-generate-api --no-optional');
shell.rm('-f', 'package-lock.json');
shell.exec('npm link');
shell.exec('npm run build');
watcher('Linking strapi-plugin-content-type-builder...', 'npm link --no-optional', false);
watcher('Building...', 'npm run build');
// Log installation duration.
const installationEndDate = new Date();