The original link
Demand background
to complete deployment before embedding code into the tag of a client website, encountered a number of difficulties in development
Demand the difficulty
Selection of packaging tool
The easiest solution is to stick with the company’s old WebPack framework, which has been upgraded to WebPack4 (see webPack Configuration Notes in the previous article), which is not optimal because it may contain some extra WebPack code. However, due to the pressure of immature technology and development time, webpack is taken as the selection. There is a need for post-optimization, considering schemes such as rollup.js, jQuery, VanillaJS (native JS)
Packaging tool Refactoring
There is a need to package all the code into a js file, so there are some changes to the framework. The changes are listed below, and the ones highlighted in red are the most important
webpack.base.babel.js
// const CopyWebpackPlugin = require('copy-webpack-plugin'); Plugin {test: /\.(jpe? G | PNG | | GIF SVG) $/, use: [{loader: 'url - loader, the options: {/ / the Inline files smaller than 10 kB, as far as possible to all of the images Inline to js limit: 100 * 1024, }, }, ], }, new webpack.optimize.MinChunkSizePlugin({ minChunkSize: Infinity, // Minimum number of characters, try to pack js into a file}), // New CopyWebpackPlugin([// 'app/favicon.ico', // 'app/manifest.json', //]. Map ((SRC) => ({from: SRC, to: path.resolve(process.cwd(), 'build') }))),Copy the code
webpack.prod.babel.js
// const LodashModuleReplacementPlugin = require('lodash-webpack-plugin'); Measurement has an impact on packaging into a JS, and the cause has not been found yet
cssDebug: true.// Enable cssDebug to avoid using MiniCssExtractPlugin, which may generate redundant CSS
entry: './app/app.js'.// Change the entry without subcontracting
output: {
filename: 'bundle.js'.// Output only one bundle.js file
},
splitChunks: false.// Turn off subcontracting optimization, same as below
runtimeChunk: false./ / new LodashModuleReplacementPlugin (), / / lodash optimization, temporary shielding, ditto
/ / new webpack. HashedModuleIdsPlugin (), / / do not need fixed chunkhash, because only one file
Copy the code
That’s how you package all your code into a bundle.js file
Bundle.js inserts the render node
The original approach was to write div tags to render in index.html, but since it is not possible to write div tags in other people’s HTML when introduced to the client, the solution is as follows
The main changes are made to the app.js entry file by actively creating a div node at the end of the body tag when rendering app.js
const render = () = > {
const root = document.createElement('div');
document.querySelector('body').appendChild(root);
ReactDOM.render(
<App />,
root
);
};
render();
Copy the code
Bundle. js introduces babel-polyfill twice
If the client also references babel-polyfill, bundle.js will fail
if (!global._babelPolyfill) { // Prevent secondary introductions
require('babel-polyfill');
}
Copy the code
Error bundle.js causes the entire client to crash
The ErrorBoundary component needs to be introduced and even if an error is reported only the bundle.js chat window introduced crashes
import React from 'react';
import PropTypes from 'prop-types';
class ErrorBoundary extends React.Component {
static propTypes = {
children: PropTypes.node,
};
constructor(props) {
super(props);
this.state = { error: null.errorInfo: null };
}
componentDidCatch(error, errorInfo) {
console.log(error, errorInfo);
// Display fallback UI
this.setState({ error, errorInfo });
// You can also log the error to an error reporting service
}
render() {
// if (this.state.hasError) {
// // You can render any custom fallback UI
// return Something went wrong.
;
// }
return this.props.children; }}export default ErrorBoundary;
Copy the code
The ErrorBoundary is then wrapped around the node that is expected to report an error
Modify the theme color
As style variables given by the backend need to be read, js variables need to be read from the CSS style. After looking for a lot of information, it is found that the ideal style is styled- Components, which can read variables from the inline CSS
However, as the size of bundle.js has reached about 1.6m, introducing styled components will be even larger, so for the moment, the style style can only be written in the code. Of course, this cannot be implemented, such as changing the CSS style in hover state. There is no good solution to this problem
Nginx-related Settings
Set cookies across domains
Since the client is an unknown domain name, it involves the problem of setting cookies across domains, which can be achieved only when the front and back ends are set simultaneously
Background knowledge
CORS divides HTTP requests into two categories, and different categories negotiate cross-domain resource sharing based on different policies.
- Simple cross-domain requests
Browsers consider a simple cross-domain request when an HTTP request occurs in one of two ways:
- The request method is GET, HEAD, or POST, and when the request method is POST, Content-type must be a value in Application/X-www-form-urlencoded, multipart/form-data, or Text /plain.
- There is no custom HTTP header in the request.
For simple cross-domain requests, all the browser has to do is add the Origin Header to the HTTP request, populate the domain where the JavaScript script resides, and request resources from servers in other domains. After receiving a simple cross-domain request, the server adds the Access-Control-Allow-Origin Header to the response Header based on the resource permission configuration. When the browser receives the response, it looks at the Access-Control-allow-Origin Header and returns the result to JavaScript if the current domain is authorized. Otherwise, the browser ignores the response.
- Are but a Preflighted cross – domain request
But are there two circumstances surrounding an HTTP request which the browser considers a Preflighted cross domain request:
- In addition to GET, HEAD and POST(only with application/ X-www-form-urlencoded, multipart/form-data, HTTP methods other than text/plain Content-type).
- Custom HTTP headers appear in the request.
Surrounding a Preflighted cross-domain request involves a browser sending a Preflighted request before a real HTTP request is sent, to check whether the server does not support a real request but a OPTIONS precheck request. The Access Control-request-method Header and access-Control-request-headers Headers are used to describe the actual Request. The browser will also add the Origin Header. After the server receives the precheck request, configure it according to the resource permissions. Add access-Control-allow-origin Headers, access-Control-allow-methods, and access-Control-allow-headers Headers to the response Header. Represents the domain, request method, and request header that allow cross-domain resource requests, respectively. In addition, the access-Control-max-age Header can be added to the server to allow the browser to use the negotiation result without sending the pre-check request for a specified period of time. The browser decides whether to proceed with a real request for cross-domain resource access based on the results returned by the OPTIONS request. The process is transparent to the caller of the real request.
XMLHttpRequest supports carrying identity information (Credential, such as cookies or HTTP authentication information) across domain requests through the withCredentials attribute. When the browser sends a request carrying the Cookie Header to the server, if the server does not respond to the Access-Control-allow-credentials Header, the browser ignores the response.
The HTTP request in question is made by an Ajax XMLHttpRequest object, and all CORS HTTP request headers can be filled by the browser without setting them in the XMLHttpRequest object. The following HTTP headers, as defined by the CORS protocol, are used to negotiate when browsers make cross-domain resource requests:
- Origin. HTTP request headers, which must be carried by any request involving CORS.
- Access – Control – Request – Method. But are not known HTTP request headers, a way of expressing a real request in a Preflighted cross domain request.
- Access – Control – Request – Headers. But are not known HTTP request headers, a custom Header list used in a Preflighted cross-domain request to represent a real request.
- Access – Control – Allow – Origin. HTTP response header that specifies the source domain that the server side allows for cross-domain resource access. The wildcard * can be used to indicate that JavaScript from any domain is allowed to Access the resource, but access-Control-Allow-Origin must specify a specific domain and cannot use the wildcard when responding to an HTTP request carrying Credential information.
- Access – Control – Allow – the Methods. HTTP response header, which specifies the list of request methods that the server allows to access resources across domains. It is typically used in response to precheck requests.
- Access – Control – Allow – Headers. HTTP response headers, a list of request headers that the server allows to access resources across domains, typically used in response to precheck requests.
- Access – Control – Max – Age. HTTP response header, used in response to a precheck request, indicating the validity time of the precheck response. During this time, the browser can decide whether it is necessary to send the real request directly, without sending the precheck request again, based on the result of the negotiation.
- Access – Control – Allow – Credentials. The HTTP response header, which does not return access-Control-allow-credentials :true, is ignored by the browser.
The back-end
Set an alias to a file that can be accessed via /im
location ^~ /im {
alias /home/frontend/pony/;
}
/bundle.js /bundle.js /bundle.js
location = /bundle.js {
alias /home/frontend/pony/bundle.js;
}
Anti-generation Settings cross domains and allow cookies to be set
location /service-tp-api/ {
add_header Access-Control-Allow-Credentials true; # whether to allow Cookie sending
add_header Access-Control-Allow-Origin $http_origin; $http_origin is the domain name of the website that references bundle.js. It cannot be set to *, otherwise the cookie will not be set successfully
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; # which HTTP methods are used
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,Coo kie,Set-Cookie,x-requested-with,content-type,pragma'; # Allow the header field to be used, you can view your request to add
if ($request_method = 'OPTIONS') {
# Cross-domain precheck
return 204;
}
# Where is the reverse generation
proxy_pass http://localhost:10602/api/im-service/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
}
Copy the code
The front end
The main thing is to add the mode and credentials fields to the fetch method, or set withCredentials in the case of XHR
export function createDebugUserInfo(data) {
return httpFetch('/service-tp-api/create-debug-user', {
method: 'POST',
data,
mode: 'cors'.credentials: 'include'}); }Copy the code
The above update is updated at 2019-5-11 17:52:48
Cursor position read writes
It is important to read and write the cursor position in order to achieve the effect of inserting an intermediate label or a newline character. Otherwise, the cursor will “flit”.
Read cursor position
function getCursorPosition(textDom) {
let cursorPos = 0;
if (document.selection) {
// IE Support
textDom.focus();
const selectRange = document.selection.createRange();
selectRange.moveStart('character', -textDom.value.length);
cursorPos = selectRange.text.length;
} else if (textDom.selectionStart || textDom.selectionStart === 0) {
// Firefox support
cursorPos = textDom.selectionStart;
}
return cursorPos;
}
Copy the code
Write cursor position
function setCursorPosition(elem, index) {
const val = elem.value;
const len = val.length;
// If the length of the text exceeds, return directly
if (len < index) return;
// Note that setTimeout delays writing, otherwise it does not take effect
setTimeout(() = > {
elem.focus();
if (elem.setSelectionRange) { // Standard browser
elem.setSelectionRange(index, index);
} else { // IE9-
const range = elem.createTextRange();
range.moveStart('character', -len);
range.moveEnd('character', -len);
range.moveStart('character', index);
range.moveEnd('character'.0); range.select(); }},0);
}
Copy the code
The above update