У меня есть стандартная структура папок, которая выглядит примерно так:
.
├── dist
| ├── vendor.js
| └── app.js
| └── index.html
├── src
| └── index.html
| └── entry.js // main app entry file
| └── entry-client.js // for client hydration
| └── entry-server.js // for server-side rendering
| └── server.js
├── package.json
Вся папка dist
создается веб-пакетом, включая файл index.html
, который только что скопирован из src
папки. Когда я хочу работать в среде разработки, файл index.html
требует /dist/app.js
и /dist/vendor.js
для работы гидратации на стороне клиента. Если их там нет, то просматриваются только страницы, отображаемые на стороне сервера. Проблема в том, что я не могу выполнять какую-либо работу по разработке, не перестраивая папку dist
полностью после каждого изменения файла, что занимает много времени и является абсолютно неэффективным способом разработки.
Моя конфигурация сборки клиента webpack делает это:
const webpack = require('webpack');
const merge = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const utils = require('./utils') // just resolves directories/files paths
const baseConfig = require('./webpack.base.config');
const isProduction = process.env.NODE_ENV === 'production';
module.exports = merge(baseConfig, {
entry: {
app: utils.resolve('/src/entry-client.js')
},
output: {
path: utils.resolve('/dist'),
filename: '[name].js', // generates app.js in ./dist folder
sourceMapFilename: '[name].js.map',
},
resolve: {
extensions: ['.js', '.vue'],
},
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendor", // generates vendor.js file in ./dist
chunks: "all",
},
},
},
},
module: {
rules: [
{
test: /\.css?$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
sourceMap: !isProduction,
// only enable hot in development
hmr: !isProduction,
// if hmr does not work, this is a forceful method.
reloadAll: true,
},
},
'css-loader',
]
},
plugins:
(isProduction ?
[
new MiniCssExtractPlugin({
filename: 'assets/css/site.css',
}),
] : [
new MiniCssExtractPlugin({
filename: 'assets/css/site.css',
hmr: true,
}),
new webpack.HotModuleReplacementPlugin(),
]
)
});
Выше работает только если я выполняю npm run build:client
. Моя установка dev выглядит следующим образом:
/**
* Setup webpack-dev-middleware and webpack-hot-middleware.
* Rebuild SSR bundle on src files change.
*
* @param {Object} app Express application
* @param {Function} onServerBundleReady Callback
*/
const setupDevServer = (app, onServerBundleReady) => {
const webpack = require('webpack');
const MFS = require('memory-fs');
const path = require('path');
const clientConfig = require('./webpack.client.config');
const serverConfig = require('./webpack.ssr.config');
// additional client entry for hot reload
clientConfig.entry.app = ['webpack-hot-middleware/client', clientConfig.entry.app];
const clientCompiler = webpack(clientConfig);
// setup dev middleware
app.use(require('webpack-dev-middleware')(clientCompiler, {
publicPath: clientConfig.output.publicPath,
serverSideRender: true,
logLevel: 'silent'
}));
// setup hot middleware
app.use(require('webpack-hot-middleware')(clientCompiler));
// watch src files and rebuild SSR bundle
global.console.log('Building SSR bundle...');
const serverCompiler = webpack(serverConfig);
const mfs = new MFS();
serverCompiler.outputFileSystem = mfs;
serverCompiler.watch({}, (error, stats) => {
if (error) throw error;
global.console.log(
`${stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false,
})}\n\n`
);
if (stats.hasErrors()) {
console.error(stats.compilation.errors);
throw new Error(stats.compilation.errors);
}
// read bundle generated by vue-ssr-webpack-plugin
const bundle = JSON.parse(
mfs.readFileSync(path.join(clientConfig.output.path, 'vue-ssr-server-bundle.json'), 'utf-8')
);
onServerBundleReady(bundle);
});
};
module.exports = setupDevServer;
Приведенная выше конфигурация setup-dev-server.js
никогда не перестраивает файлы app.js
или vendor.js
в папке ./dist
при изменениях любых других файлов, что означает, что режим разработки бессмысленно. Как решить эту проблему, чтобы любое изменение, например, Home.vue
, вызывало воссоздание app.js
и vendor.js
, поэтому мои обновления действительно работали?