如何结合Express使用Webpack打包node_modules与客户端JS
Hey there! It sounds like your current Webpack setup is treating your entire project (server + frontend) as a single bundle target—which makes sense if you started with generic docs, but we need to tweak it to focus only on your frontend assets while leaving your Express server code untouched. Let's walk through this step by step.
First: Separate Server & Frontend Code
First off, rearrange your project structure to clearly split server and client code. This makes Webpack's job way easier:
your-project/ ├── server/ # All Express code goes here (routes, middleware, etc.) │ ├── app.js │ └── ... ├── client/ # All frontend code/assets here │ ├── js/ │ │ ├── page1.js # Entry for page1 (imports jquery + script1) │ │ ├── page2.js # Entry for page2 (imports jquery) │ │ ├── page3.js # Entry for page3 (imports jquery + script1) │ │ ├── script1.js │ │ └── ... │ └── css/ (if needed) ├── public/ # Webpack outputs bundles here (served by Express) └── webpack.config.js
Webpack will only process files in client/—your Express code stays separate and runs directly (no need to bundle it!).
Configure Webpack for Multiple Frontend Entries + Code Splitting
The key goals here are:
- Create separate bundles for each page that needs JS
- Extract shared dependencies (like jquery) into a single reusable bundle to avoid duplication
- Never bundle server-side code
Here's a complete webpack.config.js example with comments explaining each part:
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); // Optional, but helps auto-inject bundles module.exports = { // Target the browser (not Node.js, which would bundle server code) target: 'web', // Define entry points for each page that needs JS entry: { page1: './client/js/page1.js', page2: './client/js/page2.js', page3: './client/js/page3.js' }, // Output bundles to the public folder (served by Express) output: { filename: '[name].bundle.js', // [name] replaces with entry key (page1, page2, etc.) path: path.resolve(__dirname, 'public'), clean: true // Cleans the public folder before each build }, // Split shared dependencies into separate bundles optimization: { splitChunks: { chunks: 'all', cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, // Match jquery and other node_modules name: 'vendor', // Name of the shared vendor bundle chunks: 'all' }, sharedScript: { test: /script1\.js$/, // Match your shared script1.js name: 'shared-script1', // Separate bundle for script1 chunks: (chunk) => chunk.name === 'page1' || chunk.name === 'page3' } } } }, // Ensure Webpack doesn't process server-side code module: { rules: [ { test: /\.js$/, exclude: /server/, // Skip server directory entirely use: 'babel-loader' // Optional, if using ES6+ features } ] }, // Optional: Auto-generate HTML files with bundles injected plugins: [ new HtmlWebpackPlugin({ filename: 'page1.html', chunks: ['vendor', 'shared-script1', 'page1'], // Include the right bundles template: './client/page1.html' // Your existing page template }), new HtmlWebpackPlugin({ filename: 'page2.html', chunks: ['vendor', 'page2'], template: './client/page2.html' }), new HtmlWebpackPlugin({ filename: 'page3.html', chunks: ['vendor', 'shared-script1', 'page3'], template: './client/page3.html' }), // page4 doesn't need a plugin since it has no JS ] };
How to Reference Bundles in Your Pages
If you're not using HtmlWebpackPlugin, you'll need to manually add script tags to each HTML file:
- page1.html:
<script src="/vendor.bundle.js"></script> <script src="/shared-script1.bundle.js"></script> <script src="/page1.bundle.js"></script> - page2.html:
<script src="/vendor.bundle.js"></script> <script src="/page2.bundle.js"></script> - page3.html:
<script src="/vendor.bundle.js"></script> <script src="/shared-script1.bundle.js"></script> <script src="/page3.bundle.js"></script> - page4.html: No script tags needed!
Critical Notes to Avoid Server Code Bundling
- Never
importorrequireserver-side files (like Express routes,app.js, etc.) in your frontend code—this is the #1 reason server code ends up in bundles. - Set
target: 'web'explicitly (Webpack's default isweb, but it's safe to define it to avoid confusion if you ever experiment with Node targets). - Use
excluderules in your module setup to skip server directories entirely.
Serving Bundles with Express
Make sure your Express app serves the public folder as static assets:
// In server/app.js const express = require('express'); const path = require('path'); const app = express(); // Serve Webpack bundles and static assets app.use(express.static('public')); // Your other routes here app.get('/page1', (req, res) => { res.sendFile(path.resolve(__dirname, '../public/page1.html')); }); // ... repeat for other pages app.listen(3000, () => console.log('Server running on port 3000'));
That should fix your issue—you'll end up with clean, split bundles only for your frontend needs, and your Express server code stays unbundled and runs as-is.
内容的提问来源于stack exchange,提问作者Renari

