现在我有了这个Webpack4&把手结构
src/
├── assets/
│ ├── css/
│ ├── fonts/
│ ├── img/
│ ├── js/
│ ├── scss/
│ └── vendor/
├── helpers/
│ ├── repeat.js
│ └── compare.js
├── partials/
│ ├── header.hbs
│ └── footer.hbs
├── index.hbs
├── subpage1.hbs
└── subpage2.hbs
它与很好地配合
dest/
├── assets/
│ ├── css/
│ ├── fonts/
│ ├── img/
│ ├── js/
│ ├── scss/
│ └── vendor/
├── index.html
├── subpage1.html
└── subpage2.html
我同意,但客户希望有subpage1.html
、subpage2.html
。。。子文件夹/subpage1/
等包含另一个index.html,这样他们就可以在没有任何htaccess的情况下拥有漂亮的url,而且正如他们所说的那样,它更可读:-/
问题是如何复制子目录并处理其中的句柄文件:
src/
├── assets/
│ ├── css/
│ ├── fonts/
│ ├── img/
│ ├── js/
│ ├── scss/
│ └── vendor/
├── helpers/
│ ├── repeat.js
│ └── compare.js
├── partials/
│ ├── header.hbs
│ └── footer.hbs
├── subpage1/
│ └── index.hbs
├── subpage2/
│ └── index.hbs
└── index.hbs
如果我成功地完成了这一步,将面临另一个挑战——处理相对路径,并使它们成为图像、css、bundle.js 的绝对路径
这是我的webpack常见配置:
const path = require('path');
const webpack = require('webpack');
const handlebars = require('handlebars');
const utils = require('handlebars-utils');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const vars = require('./variables.js');
const glob = require('glob');
const generateHTMLPlugins = () =>
glob.sync('./src/*.{html,hbs}').map(item => {
return new HtmlWebpackPlugin({
filename: path.parse(item).name + '.html',
template: item
});
});
module.exports = {
context: vars.relativePath,
entry: [
vars.src.relativePath + vars.src.assetsPath + 'js/scripts.js'
],
output: {
path: vars.dist.relativePath,
filename: vars.dist.assetsPath + 'js/bundle.js'
},
plugins: [
new webpack.LoaderOptionsPlugin({
options: {
handlebarsLoader: {}
}
}),
new CopyWebpackPlugin([ // images folder
{
from: vars.src.relativePath + vars.src.assetsPath + 'img',
to: vars.dist.relativePath + vars.dist.assetsPath + 'img'
}
]),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
Popper: ['popper.js', 'default']
}),
...generateHTMLPlugins()
],
module: {
rules: [
{
test: /.js?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /.hbs$/,
loader: 'handlebars-loader',
query: {
helperDirs: [vars.src.relativePath + 'helpers'],
partialDirs: [vars.src.relativePath + 'partials'],
precompileOptions: {
knownHelpersOnly: false,
},
}
},
{ // Compile and merge sass + css
test: /.s?css/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
sourceMap: (this.mode == 'production') ? false : true
}
},
{
loader: 'css-loader',
options: {
sourceMap: (this.mode == 'production') ? false : true
}
},
{
loader: 'postcss-loader',
options: {
plugins: [
require('autoprefixer'),
require('cssnano')({
discardComments: { removeAll: true }
}),
],
sourceMap: (this.mode == 'production') ? false : true
}
},
{
loader: 'sass-loader',
options: {
sourceMap: (this.mode == 'production') ? false : true
}
}
]
},
{ // Fonts
test: /.woff($|?)|.woff2($|?)|.ttf($|?)|.eot($|?)|.svg($|?)/,
exclude: /img//,
use: {
loader: "file-loader",
options: {
name: '[name].[ext]',
publicPath: '../fonts/',
outputPath: vars.dist.assetsPath + 'fonts/',
}
},
},
{ // Context images
test: /.(jpe?g|png|gif|svg)/,
exclude: /font/,
use: {
loader: "file-loader",
options: {
name: '[name].[ext]',
publicPath: '../img/',
outputPath: vars.dist.assetsPath + 'img/'
}
}
},
]
}
};
Webpack变量:
const path = require('path');
const relativePath = path.resolve(__dirname, '../');
const argv = require('yargs').argv;
const theme = (argv.name === undefined) ? 'default' : argv.name
module.exports = {
relativePath: relativePath,
dist: {
path: 'dist/',
relativePath: relativePath + '/dist/',
assetsPath: 'assets/'
// assetsPath: 'assets/' + theme + '/'
},
src: {
path: 'src/',
relativePath: relativePath + '/src/',
assetsPath: 'assets/'
// assetsPath: 'assets/' + theme + '/'
}
}
和生产配置
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const AggressiveMergingPlugin = require('webpack/lib/optimize/AggressiveMergingPlugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const vars = require('./variables.js');
module.exports = merge(common, {
output: {
path: vars.dist.relativePath,
filename: vars.dist.assetsPath + 'js/bundle.js'
},
mode: 'production',
plugins: [
new MiniCssExtractPlugin({
filename: vars.dist.assetsPath + 'css/style.min.css',
allChunks: true,
}),
new UglifyJsPlugin(), //minify everything
new AggressiveMergingPlugin(), //Merge chunks
new CleanWebpackPlugin([vars.dist.path],{
root: vars.relativePath
})
]
})
所以。。我找到了一个解决方案。。也许不是一个优雅的,但它是有效的。这是为递归hbs到html除了部分目录:
glob.sync('./src/**/*.{html,hbs}', {"ignore": ['./src/partials/*']} ).map(item => {
return new HtmlWebpackPlugin({
// filename: path.parse(item).name + '.html',
filename: path.resolve(__dirname, '../') + path.parse(item).dir.replace('./src', '/dist') + '/' + path.parse(item).name + '.html',
template: item
});
});
并最终设置公共的绝对路径
output: {
path: vars.dist.relativePath,
publicPath: '/',
filename: vars.dist.assetsPath + 'js/bundle.js'
},