Create SRC directories. Create front-end directories and node directories
The general directory is divided into
├ ─ ─ the config │ ├ ─ ─ htmlAfterWebpackPlugin. Js │ ├ ─ ─ webpack. Development. The js │ └ ─ ─ webpack. Production. The js ├ ─ ─ gulpfile. Js ├ ─ ─ Package. The json ├ ─ ─ postcss. Config. Js ├ ─ ─ the SRC │ ├ ─ ─ nodeuii │ │ ├ ─ ─ app. Js │ │ ├ ─ ─ the config │ │ │ └ ─ ─ index. The js │ │ ├ ─ ─ Controllers │ │ │ ├ ─ ─ ControllerInit. Js │ │ │ └ ─ ─ IndexController, js │ │ ├ ─ ─ middlewares │ │ │ └ ─ ─ errHandler. Js │ │ ├ ─ ─ Models │ │ │ └ ─ ─ IndexModel. Js │ │ └ ─ ─ views │ │ └ ─ ─ index. The HTML │ └ ─ ─ webapp │ ├ ─ ─ views │ │ ├ ─ ─ common │ │ │ └ ─ ─ Layout. HTML │ │ └ ─ ─ index │ │ ├ ─ ─ the index - index. Entry. Js │ │ └ ─ ─ pages │ │ └ ─ ─ index. The HTML │ └ ─ ─ widgets │ └ ─ ─ the header │ ├ ─ ─ │ ├─ ├─ ├─ ├─ ├.org.txt │ ├─ ├.org.txt │ ├─ ├.org.txt │ ├─ ├.org.txtCopy the code
With the project body created, start creating the automated build process
Automated build process
Tool: gulp gulp-babel gulp-watch
1. npm init -y
2. Create gulpfile.js and write the automated process
const gulp = require('gulp');
const babel = require('gulp-babel'); // Automatically compile es6 to ES5
const watch = require('gulp-watch'); // gulp listens for file changes
const rollup = require('gulp-rollup'); // Do file cleaning, delete useless code
const replace = require ('rollup-plugin-replace'); // Replace files when they are cleaned
const gulpSequence = require('gulp-sequence') // gulp task execution order<! --> gulp.task()'buildenv'.function () {
return watch('./src/nodeuii/**/*.js',
{
ignoreInitial: false It needs to be executed before the first file modification, that is, immediately after watch() is called
}, () => {
gulp.src('./src/nodeuii/**/*.js')
.pipe(babel({
babelrc: false.// Ignore the. Babelrc file under the root directory
"plugins": [["transform-decorators-legacy"."transform-es2015-modules-commonjs", {
"allowTopLevelThis": true
}]
]
}))
.pipe(gulp.dest('dist')); // Output to the dist folder})});<! Build task of production environment, compile ES6 to ES5gulp.task('buildprod', function () { gulp.src('./src/nodeuii/**/*.js') .pipe(babel({ ignore: ['./src/nodeuii/config/*.js'], babelrc: false, "plugins": [ ["transform-decorators-legacy", "transform-es2015-modules-commonjs", { "allowTopLevelThis": true }] ] })) .pipe(gulp.dest('dist')); }); // Start the cleaning stream, Tree-shaking gulp.task('buildconfig', () => { gulp.src('./src/nodeuii/**/*.js') .pipe(rollup({ output:{ format: 'CJS', / / output files to the format of the commonjs}, input: '. / SRC/nodeuii/config/index. Js', / / the specified file rollup plugins: [ replace({ 'process.env.NODE_ENV': Json.stringify ('production') // use rollup-plugin-replace to replace variables in files such as})]})).pipe(gulp.dest('./dist')); }); let _task = ['buildenv']; if (process.env.NODE_ENV == 'production') { _task = gulpSequence(['buildprod','buildconfig']); } gulp.task('default', _task);Copy the code
Tree-shaking
Gulp-rollup rollup-plugin-replace Gulp-sequence (gulp-rollup) : gulp-rollup (gulp-rollup) : gulp-rollup (gulp-rollup) : gulp-rollup
App.js file
const init = () => {
if (process.env.NODE_ENV == 'development') {
const developConfig = {
port: 8081
}
config = _.extend(config, developConfig);
}
if (process.env.NODE_ENV == 'production') {
const prodConfig = {
port: 8081
}
config = _.extend(config, prodConfig);
}
return config;
}
export default init();
Copy the code
The environment is cleaned online
const init = () => {
{
const prodConfig = {
port: 8081
};
config = _.extend(config, prodConfig);
}
return config;
};
var index = init();
module.exports = index;
Copy the code
A careful comparison of the two pieces of code reveals that, after cleaning, only the code needed for the production environment is left, simplifying the code;
3. Write the main entry file app.js
The node uses KOA2 + KOa-simple-router + KOa-swig + Log4JS
import Koa from 'koa' // koa 2.x
import router from 'koa-simple-router'
import render from 'koa-swig';
import log4js from "log4js";
import controllerInit from './controllers/ControllerInit';
import config from './config'
import errorHander from './middlewares/errHandler';
const app = new Koa();
<! -- Koa static file specifies middleware koa-static -->
const serve = require('koa-static');
<! The co module can operate asynchronously -->
const co = require('co');
<! View layer files -->app.context.render = co.wrap(render({ root: config.viewDir, autoescape: True, varControls:["[[","]]"], // Set Vue {{}} cache: 'memory', // disable, set to false ext: 'html', })); log4js.configure({ appenders: { cheese: { type: "file", filename: "./logs/rys.log" } }, categories: { default: { appenders: ["cheese"], level: "error" } } }); // Handling error center const logger = log4js.getLogger("cheese"); errorHander.error(app,logger); . / / all focus on routing controllerInit getAllRouters (app, the router); Use (serve(config.staticdir)) app.listen(config.port,() => {console.log(' app is listening on ${config.port}`) })Copy the code
Note:
Koa: EXPRESSIVE HTTP middleware framework for Node.js that makes Web applications and apis more enjoyable to write koA-static: KOA static files specify middleware koa-static co: Generator based NodeJS and browser control flow well, using Promises, allows you to write non-blocking code in a very good way koA-swig: Swig based KOA view rendering with support for tags, filters and extensions. Koa 2X is used with CO module when rendering pages using KOA-swiglog4js: log management cross-env: setting environment variablesCopy the code
Swig is a JS template engine
Use extends and block to implement template inheritance layout.html
- Layout.html is a public page body
<! DOCTYPE html> <html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
{% block head %}{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
Copy the code
- The index. HTML include template contains a template to the current location that will use the current context
{% extends '.. /common/layout. HTML '%} {% block title %} home {% endBlock %} {% block content %} {% include ".. /.. /widgets/header/header.html" %} {% endblock %}Copy the code
After node side testing is complete, start writing front-end automation builds
4. Write a webpack. Config. Js
const argv = require('yargs-parser')(process.argv.slice(2))
const merge = require('webpack-merge')
const glob = require('glob')
const files = glob.sync('./src/webapp/views/**/*.entry.js')
const _mode = argv.mode || 'development'
const _modeflag = _mode === 'production'
const _mergeConfig = require(`./config/webpack.${_mode}.js`)
const { join } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const htmlAfterWebpackPlugin = require('./config/htmlAfterWebpackPlugin.js')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
let _entry = {} // Webpack public entry
let _plugins = [] // WebPack public plug-in
for (let item of files) {
//index-index.entry.js -> index.index.js
if (/.+\/([a-zA-Z]+-[a-zA-Z]+)(\.entry\.js$)/g.test(item)) {
const entrykey = RegExp. $1
// console.log(entrykey);
_entry[entrykey] = item
//dist Outer folder name template inner HTML name
const [dist, template] = entrykey.split(The '-')
_plugins.push(
new HtmlWebpackPlugin({
filename: `.. /views/${dist}/pages/${template}.html`.template: `src/webapp/views/${dist}/pages/${template}.html`.minify: {
collapseWhitespace: _modeflag,
removeAttributeQuotes: _modeflag
},
inject: false}}}))let webpackConfig = {
entry: _entry,
output: {
path: join(__dirname, './dist/assets'),
publicPath: '/'.filename: 'scripts/[name].boudle.js'
},
module: {
rules: [{test: /\.(sa|sc|c)ss$/.use: [
MiniCssExtractPlugin.loader,
'css-loader'.'postcss-loader'.'sass-loader']]}},watch: !_modeflag,
watchOptions: {
ignored: /node_modules/.aggregateTimeout: 300.poll: 1
},
optimization: {
splitChunks: {
chunks: 'async'.minSize: 30000.maxSize: 0.minChunks: 1.maxAsyncRequests: 6.maxInitialRequests: 4.automaticNameDelimiter: '~'.cacheGroups: {
commons: {
chunks: 'initial'.minChunks: 2.minSize: 0.name: 'conmons'}}},runtimeChunk: {
name: 'runtime'}},plugins: [
..._plugins,
new CleanWebpackPlugin({}),
new MiniCssExtractPlugin({
filename: 'styles/[name].[hash:5].css'
}),
new htmlAfterWebpackPlugin({ options: ' '}})]module.exports = merge(webpackConfig, _mergeConfig)
Copy the code
5. Write webpack.develop.js (development environment)
const CopyWebpackPlugin = require('copy-webpack-plugin')
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
plugins: [
// Layout.html in views
new CopyWebpackPlugin([
{
from: path.join(__dirname, '.. /src/webapp/views/common/layout.html'),
to: '.. /views/common/layout.html'}]),new CopyWebpackPlugin(
[
{
from: path.join(__dirname, '.. /src/webapp/widgets/'),
to: '.. /widgets'}, {copyUnmodified: true.ignore: ['*.js'.'*.css']}),new MiniCssExtractPlugin({
filename: 'styles/[name].css'}})]Copy the code
6. Write webpack.production.js (production environment)
const CopyWebpackPlugin = require('copy-webpack-plugin')
const minify = require('html-minifier').minify
const path = require('path')
module.exports = {
output: {
filename: 'scripts/[name].[hash:5].bundle.js'
},
plugins: [
// Layout.html in views
new CopyWebpackPlugin([
{
from: path.join(
__dirname,
'.. / ' + 'src/webapp/views/common/layout.html'
),
to: '.. /views/common/layout.html',
transform (content, path) {
return minify(content.toString('utf-8'), {
collapseWhitespace: true})}}]),new CopyWebpackPlugin(
[
{
from: path.join(__dirname, '.. / ' + 'src/webapp/widgets/'),
to: '.. /widgets',
transform (content, path) {
return minify(content.toString('utf-8'), {
collapseWhitespace: true}}}], {copyUnmodified: true.ignore: ['*.js'.'*.css']})]}Copy the code
7. Write custom webpack – plugin = > htmlAfterWebpackPlugin. Js (to deal with documents after packaging)
const pluginName = 'htmlAfterWebpackPlugin'
const assetsHelp = data= > {
let css = [],
js = []
const dir = {
js: item= > `<script src="${item}"></script>`.css: item= > `<link rel="stylesheet" href="${item}"/ > `
}
for (let jsitem of data.js) {
js.push(dir.js(jsitem))
}
for (let cssitem of data.css) {
css.push(dir.css(cssitem))
}
return{ css, js } } <! -- check the documentation for htML-webpack-plugin v3, which contains hooks -->class htmlAfterWebpackPlugin {
apply (compiler) {
compiler.hooks.compilation.tap(pluginName, compilation => {
compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tap(
pluginName,
htmlPluginData => {
let _html = htmlPluginData.html
const result = assetsHelp(htmlPluginData.assets)
console.log(result)
// Use Cheerio vue SSR to insert different positions according to your template Settings
_html = _html.replace('<! --injectcss-->', result.css.join(' '))
_html = _html.replace('<! --injectjs-->', result.js.join(' '))
htmlPluginData.html = _html
}
)
})
}
}
module.exports = htmlAfterWebpackPlugin
Copy the code
Package the project and run it
yarn client:dev
yarn start:dev
Copy the code
Visit: http://localhost:8081
Note:
Yargs-parser: Yargs helps you build the interactive command line tool package.json by parsing parameters and generating elegant user interfaces:"scripts": {
"start:dev": "cross-env NODE_ENV=development supervisor ./dist/app.js"."build:dev": "gulp"."build:prod": "cross-env NODE_ENV=production gulp"."docs": "jsdoc ./src/nodeuii/**/*.js -d ./docs/jsdocs"."client:dev": "webpack --mode development"."client:prod": "webpack --mode production"
},
webpack.config.js:
var argv = require('yargs-parser')(process.argv.slice(2)); Console. log(argv.mode) // Development or production webpack-merge: Merge objects Many times, we need to do different operations for different environments. Webpack.product. js // Production environment required code webpack.dev.js // development environment required code glob: Pattern matching files used by the shell, such as asterisks. var glob = require("glob"); // options Optional glob("**/*.js", options, function(er, files) {// files is an array of filename. // If the option 'nonull' is set and no match is found, files is ["**/*.js"] // er is an error object or null. })Copy the code
For multiple files, the repeated file configuration is implemented to automatically get the file to be configured, and call in a loop; Eg: Use the glob module to get files
/ / into the glob
var glob = require('glob');
// Read all HTML files in the SRC directory
var files = glob.sync('./src/*.html');
var entry={};
var plugins=[];
// Loop the file
files.forEach(function(item,i){
//item is similar to./ SRC /index.html
var htmlName=item.slice(item.lastIndexOf("/") + 1);
// The last filename to be generated only needs the last name index.html
var name=htmlName.split(".") [0];
// Add to the entry entry and specify the directory to generate the file
entry["page/"+name+"/"+name]='./src/js/'+name+'.js'
// Generate an htmlWebpackPlugin instance
plugins.push(
new htmlWebpackPlugin({
template:item,
filename:htmlName,
chunks: ["page/"+name+"/"+name]
})
)
});
module.exports={
entry:entry,
output: {filename:"[name].[chunkhash].js".path:path.resolve(__dirname,'dist'),},module: {rules:[
{
test: /\.js$/.exclude: /node_modules/.use: {
loader: 'babel-loader'}}},],plugins:plugins
}
// Use glob.sync to read files and loop through them. The loop takes care of the parts that need to be done manually.
Copy the code
Generate jsdocs
"docs": "jsdoc ./src/nodeuii/**/*.js -d ./docs/jsdocs"
Copy the code
Source address link:
Preliminary Discussion on front-end architecture
Welcome to communicate
Reference Documents:
- Lodash Chinese document; Lodash is a consistent, modular, high-performance JavaScript utility library.
- Jsdoc is a tool that generates API documents for javascript applications, libraries, and modules based on comments in javascript files
- Cross-env introduces scripts that run cross-platform Settings and use environment variables
- Rollup module packaging; Implement code cleaning
- Rollup Chinese document
- Co source code analysis
- Log4js is completely explained
- yargs-parser
- Webpack – the use of the merge
- The Node glob grammar
- copy-webpack-plugin
- HTML – webpack – plugin explanation
- extract-text-webpack-plugin
- HTML – minifier;