Integrating ThinkJS with Vue2 for a Multi‑Page Project: Full Configuration Guide
This article provides a step‑by‑step tutorial on building a simple ThinkJS + Vue2 project with separate user and admin pages, covering directory layout, proxy setup, multi‑page webpack configuration, server routing, API creation, adding new pages, and production build deployment.
Today we discuss how to combine two powerful frameworks, ThinkJS and Vue2, to build a simple project that has both a user side and an admin interface, each implemented as a separate single‑page application served by ThinkJS APIs.
Project directory structure is shown below:
.
├── README.md
├── client
│ ├── README.md
│ ├── build
│ ├── config
│ ├── package.json
│ ├── src
│ │ ├── components
│ │ ├── modules
│ │ └── pages
│ │ ├── admin
│ │ └── index
│ └── static
└── server
├── src
│ ├── bootstrap
│ ├── config
│ ├── controller
│ │ ├── admin
│ │ ├── base.js
│ │ ├── home
│ │ └── index.js
│ ├── logic
│ └── model
├── view
│ ├── admin.html
│ └── index.html
└── www
└── staticClient configuration starts with a Vue‑CLI generated project using webpack. In config/index.js a proxyTable is added to forward /api requests to the ThinkJS server:
proxyTable: {
'/api': {
target: 'http://localhost:8360/api/',
changeOrigin: true,
pathRewrite: { '^/api': '/' }
}
},To turn the single‑page app into a multi‑page application, the project structure is adjusted: a new folder src/pages/index is created and the original files ( src/assets , src/router , src/App.vue , src/main.js , ./index.html ) are moved there, renaming main.js to index.js .
In build/utils.js the following helper functions are added to generate entry points and HTML plugins for each page using glob :
exports.entries = function() {
var entryFiles = glob.sync(PAGE_PATH + '/*/*.js');
var map = {};
entryFiles.forEach((filePath) => {
var filename = filePath.substring(filePath.lastIndexOf('/') + 1, filePath.lastIndexOf('.'));
map[filename] = filePath;
});
return map;
};
exports.htmlPlugin = function() {
let entryHtml = glob.sync(PAGE_PATH + '/*/*.html');
return entryHtml.map((filePath) => {
let filename = filePath.substring(filePath.lastIndexOf('/') + 1, filePath.lastIndexOf('.'));
let conf = {
template: filePath,
filename: filename + '.html',
chunks: ['manifest', 'vendor', filename],
inject: true
};
if (process.env.NODE_ENV === 'production') {
conf = merge(conf, {
minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true },
chunksSortMode: 'dependency'
});
}
return new HtmlWebpackPlugin(conf);
});
};The webpack entry configuration in build/webpack.base.conf.js is replaced with utils.entries() , and the plugin list in both webpack.dev.conf.js and webpack.prod.conf.js now includes utils.htmlPlugin() .
Additional pages are created under src/pages (e.g., admin , 404 ) with corresponding HTML templates, and the historyApiFallback rewrites in the dev server are updated to serve the correct HTML files for / , /admin , and any unknown routes.
Server configuration uses ThinkJS’s think-cli . In src/config/router.js routes are added to map API calls and page requests:
module.exports = [
[/^\/api\/(.*)/i, '/:1'],
[/^\/$/i, '/'],
[/^\/admin\/?$/i, '/index/admin'],
[/\//, 'index/_404', 'get']
];The main controller ( src/controller/index.js ) renders the appropriate HTML files:
class Index extends Base {
indexAction() { return this.display('index.html'); }
adminAction() { return this.display('admin.html'); }
_404Action() { return this.display('404.html'); }
}Any controller method exposed under /api becomes reachable via /api/controller/action . An example test controller returns a JSON response:
{ "errno": 0, "errmsg": "", "data": "test" }To add a new page abc , a folder src/pages/abc with abc.html is created, the dev server’s historyApiFallback rewrites are extended, and a new abcAction is added to the controller along with a matching route entry.
Production build is performed by running npm run build inside the client directory. The generated dist/*.html files are copied to the server’s view directory, and dist/static is moved to server/www . After deployment the server serves the pre‑built assets.
Following these steps results in a fully functional ThinkJS + Vue2 multi‑page application with separate user and admin interfaces, API endpoints, and a ready‑to‑deploy production build.
360 Tech Engineering
Official tech channel of 360, building the most professional technology aggregation platform for the brand.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.