Я только что приобрел тему Keen у Bootstrap и, следуя инструкциям к письму, столкнулся с ошибкой при выполнении npm run build (см. Ниже). Я посмотрел на файл web pack.config. js (см. Ниже), но так как это то, что я не изучил подробно, я не могу понять, в чем проблема. Любая помощь будет принята с благодарностью, спасибо!
Ошибка вывода:
0 info it worked if it ends with ok
1 verbose cli [ '/usr/local/bin/node', '/usr/local/bin/npm', 'run', 'build' ]
2 info using npm@6.13.6
3 info using node@v13.8.0
4 verbose run-script [ 'prebuild', 'build', 'postbuild' ]
5 info lifecycle keen@1.4.2~prebuild: keen@1.4.2
6 info lifecycle keen@1.4.2~build: keen@1.4.2
7 verbose lifecycle keen@1.4.2~build: unsafe-perm in lifecycle true
8 verbose lifecycle keen@1.4.2~build: PATH: /usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/julian/Downloads/compile/node_modules/.bin:/Users/julian/.rvm/gems/ruby-2.6.5/bin:/Users/julian/.rvm/gems/ruby-2.6.5@global/bin:/Users/julian/.rvm/rubies/ruby-2.6.5/bin:/Users/julian/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/VMware Fusion.app/Contents/Public/:/Users/julian/.rvm/bin
9 verbose lifecycle keen@1.4.2~build: CWD: /Users/julian/Downloads/compile
10 silly lifecycle keen@1.4.2~build: Args: [ '-c', 'webpack' ]
11 silly lifecycle keen@1.4.2~build: Returned: code: 1 signal: null
12 info lifecycle keen@1.4.2~build: Failed to exec build script
13 verbose stack Error: keen@1.4.2 build: `webpack`
13 verbose stack Exit status 1
13 verbose stack at EventEmitter.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/index.js:332:16)
13 verbose stack at EventEmitter.emit (events.js:321:20)
13 verbose stack at ChildProcess.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/lib/spawn.js:55:14)
13 verbose stack at ChildProcess.emit (events.js:321:20)
13 verbose stack at maybeClose (internal/child_process.js:1026:16)
13 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:286:5)
14 verbose pkgid keen@1.4.2
15 verbose cwd /Users/julian/Downloads/compile
16 verbose Darwin 19.3.0
17 verbose argv "/usr/local/bin/node" "/usr/local/bin/npm" "run" "build"
18 verbose node v13.8.0
19 verbose npm v6.13.6
20 error code ELIFECYCLE
21 error errno 1
22 error keen@1.4.2 build: `webpack`
22 error Exit status 1
23 error Failed at the keen@1.4.2 build script.
23 error This is probably not a problem with npm. There is likely additional logging output above.
24 verbose exit [ 1, true ]
webpack.config. js:
/**
* Main file of webpack config.
* Please do not modified unless you know what to do
*/
const path = require("path");
const glob = require("glob");
const webpack = require("webpack");
const fs = require("fs");
const parser = require("comment-parser");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const WebpackRTLPlugin = require("webpack-rtl-plugin");
const TerserJSPlugin = require("terser-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const WebpackMessages = require("webpack-messages");
const ExcludeAssetsPlugin = require("webpack-exclude-assets-plugin");
const atob = require("atob");
const slash = require("slash");
const del = require("del");
// optional
const ReplaceInFileWebpackPlugin = require("replace-in-file-webpack-plugin");
/**
* Known issues:
* 1) Remove webpack bootstrap for single-module apps
* https://github.com/webpack/webpack/issues/2638
*/
// arguments/params from the line command
const args = {};
// remove first 2 unused elements from array
const argv = JSON.parse(process.env.npm_config_argv).cooked.slice(2);
argv.forEach((arg, i) => {
if (arg.match(/^--/)) {
const next = argv[i + 1];
args[arg] = true;
if (next && !next.match(/^--/)) {
args[arg] = argv[i + 1];
}
}
});
// read parameters from the command executed by user
const rtl = args["--rtl"] || false;
const prod = args["--prod"] || false;
const css = args["--css"] || true;
const js = args["--js"] || true;
// theme name
const themeName = "keen";
// global variables
const release = true;
const apiUrl = false; // boolean
const rootPath = path.resolve(__dirname, "..");
const frameworkPath = path.resolve(__dirname, "..");
const distPath = rootPath + "/dist";
const configPath = rootPath + "/tools";
const assetDistPath = distPath + "/assets";
const srcPath = rootPath + "/src/assets";
// page scripts and styles
const pageScripts = glob.sync(srcPath + "/js/pages/**/!(_*).js");
const pagesScss = glob.sync(srcPath + "/sass/pages/**/!(_*).scss");
const extraPlugins = [];
const filesConfig = [];
const imageReference = {};
const exclude = [];
const nodeMedia = [];
// remove older folders and files
// (async () => {
// await del.sync(assetDistPath, {force: true});
// })();
// get all assets config
let files = glob.sync(configPath + "/webpack/**/*.js");
// parse comments to get the output location
files.forEach((filename) => {
// get file content
const text = fs.readFileSync(filename).toString();
// use parser plugin to parse the comment.
const parsed = parser(text);
if (parsed.length > 0 && parsed[0].tags.length > 0) {
// push to list
filesConfig.push({
filename: filename,
params: parsed[0].tags,
});
}
});
const entries = {};
filesConfig.forEach((file) => {
let output = "";
file.params.forEach((param) => {
// get output path
if (param.tag === "output") {
output = param.name;
}
});
entries[output] = file.filename;
});
// process skin scss
const skinScss = glob.sync(srcPath + "/sass/**/skins/**/!(_*|style*).scss");
skinScss.forEach((file) => {
const matched = file.match(/sass\/global\/layout\/(.*?)\.scss$/);
if (matched) {
entries["css/skins/" + matched[1].replace(/\/skins\//, "/")] = file;
}
});
// process pages scss
pagesScss.forEach((file) => {
const matched = file.match(/\/(pages\/.*?)\.scss$/);
if (matched) {
// keep image reference for output path rewrite
const imgMatched = fs.readFileSync(file).toString().match(/['|"](.*?\.(gif|png|jpe?g))['|"]/g);
if (imgMatched) {
imgMatched.forEach((img) => {
img = img.replace(/^['|"](.+(?=['|"]$))['|"]$/, '$1');
imageReference[path.basename(img)] = "css/" + matched[1] + ".css";
});
}
entries['css/' + matched[1]] = file;
}
});
// auto get page scripts from source
pageScripts.forEach(function (jsPath) {
const matched = jsPath.match(/js\/(pages\/.*?)\.js$/);
entries["js/" + matched[1]] = jsPath;
});
if (release) {
// copy html by demo
extraPlugins.push(new CopyWebpackPlugin([{
from: rootPath + "/src",
to: distPath,
}]));
}
if ((/true/i).test(rtl)) {
// enable rtl for css
extraPlugins.push(new WebpackRTLPlugin({
filename: "[name].rtl.css",
}));
}
if (!(/true/i).test(js)) {
// exclude js files
exclude.push('\.js$');
}
if (!(/true/i).test(css)) {
// exclude css files
exclude.push('\.s?css$');
}
if (exclude.length) {
// add plugin for exclude assets (js/css)
extraPlugins.push(new ExcludeAssetsPlugin({
path: exclude
}));
}
if (apiUrl) {
// replace api url to point to server
extraPlugins.push(new ReplaceInFileWebpackPlugin([{
dir: assetDistPath + "/js",
test: /\.js$/,
rules: [{
search: /inc\/api\//i,
replace: 'https://keenthemes.com/' + themeName + '/tools/preview/'
}]
}]));
}
const mainConfig = function () {
return {
// enabled/disable optimizations
mode: (/true/i).test(prod) ? "production" : "development",
// console logs output, https://webpack.js.org/configuration/stats/
stats: "errors-warnings",
performance: {
// disable warnings hint
hints: false
},
optimization: {
// js and css minimizer
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
},
entry: entries,
output: {
// main output path in assets folder
path: assetDistPath,
// output path based on the entries' filename
filename: "[name].js"
},
resolve: {
alias: {
"morris.js": "morris.js/morris.js",
"jquery-ui": "jquery-ui",
}
},
plugins: [
// webpack log message
new WebpackMessages({
name: themeName,
logger: str => console.log(`>> ${str}`)
}),
// create css file
new MiniCssExtractPlugin({
filename: "[name].css",
}),
// copy media
new CopyWebpackPlugin([{
from: srcPath + "/media",
to: assetDistPath + "/media",
}]),
{
apply: (compiler) => {
// hook name
compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
filesConfig.forEach((file) => {
let output = "";
file.params.forEach((param) => {
// get output path
if (param.tag === "output") {
output = param.name;
}
if (param.tag === "images") {
param.name.split(",").forEach((file) => {
if (file) {
const outputPath = assetDistPath + "/" + pathWithoutFile(output) + "/images/";
// create dir
fs.mkdirSync(outputPath, {recursive: true});
// copy image
fs.copyFileSync(fs.realpathSync(srcPath + "/" + file), outputPath + path.basename(file));
}
});
}
});
});
});
}
},
].concat(extraPlugins),
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
],
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "sass-loader",
options: {
sourceMap: true,
// // use for separate css pages (custom pages, eg. wizard, invoices, etc.)
// includePaths: demos.map((demo) => {
// return slash(srcPath) + "/sass/theme/demos/" + demo;
// })
}
},
]
},
{
test: /\.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
include: [
path.resolve(__dirname, "node_modules"),
rootPath,
frameworkPath,
],
use: [
{
loader: "file-loader",
options: {
// prevent name become hash
name: "[name].[ext]",
// move files
outputPath: "plugins/global/fonts",
// rewrite path in css
publicPath: "fonts",
}
}
]
},
{
test: /\.(gif|png|jpe?g)$/,
include: [
path.resolve(__dirname, "node_modules"),
rootPath,
],
use: [{
loader: "file-loader",
options: {
// prevent name become hash
name: "[name].[ext]",
// move files
outputPath: (url, resourcePath) => {
// look for node_modules plugin
const matched = slash(resourcePath).match(/node_modules\/(.*?)\//);
if (matched) {
for (let i = 0; i < filesConfig.length; i++) {
if (filesConfig[i].filename.match(new RegExp(matched[1]))) {
let output = "";
filesConfig[i].params.forEach((param) => {
// get output path without filename
if (param.tag === "output") {
output = pathWithoutFile(param.name);
}
});
nodeMedia[url] = output + "/images/" + url;
return output + "/images/" + url;
}
}
}
// the rest of images put in media/misc/
return "media/misc/" + url;
},
// rewrite path in css
publicPath: (url, resourcePath) => {
if (imageReference[url]) {
// fix image rewrite path
const filePath = pathWithoutFile(imageReference[url]);
return slash(path.relative(assetDistPath + "/" + filePath, assetDistPath + "/media") + "/" + url);
}
if (nodeMedia[url]) {
return "images/" + url;
}
return "../../media/misc/" + url;
},
}
}]
},
]
},
// webpack dev server config
devServer: {
contentBase: distPath,
compress: true,
port: 3000
}
}
};
module.exports = function () {
return [mainConfig()];
};
function pathWithoutFile(filname) {
return filname.substring(0, filname.lastIndexOf("/"));
}