何したいの?
https://github.com/nuxt-community/express-template
こちらのNuxt.js公式テンプレートを使って開発中の出来事になります。
MySQLに接続するためにサーバーサイドにSequelizeを導入したのですが、
いざnpm run dev
すると
Error: Cannot find module '/home/User/Project-Name/build/server/models/user.js'
というエラーが。
buildフォルダにはjsファイルとソースマップだけ。
あれぇ?
原因を探ろう
Nuxt.jsは元からwebpackによるJSファイルのバンドル機能が組み込まれています。
requireやimport文が一行でも書かれていれば見逃すことなく1ファイルにまとめてくれるすごい奴のはずなんですが。
sequelizeのソースを眺める
'use strict';
require('dotenv').config();
var fs = require('fs');
var path = require('path');
var Sequelize = require('sequelize');
var basename = path.basename(__filename);
var env = process.env.NODE_ENV || 'development';
var config = require(__dirname + '/../config/config.json')[env];
var db = {};
if (config.use_env_variable) {
console.log(process.env[config.use_env_variable]);
var sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
var sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => {
var model = sequelize['import'](path.join(__dirname, file)); // <-- モデル読み込みはここ!
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
//382行目から
import(path) {
// is it a relative path?
if (Path.normalize(path) !== Path.resolve(path)) {
// make path relative to the caller
const callerFilename = Utils.stack()[1].getFileName();
const callerPath = Path.dirname(callerFilename);
path = Path.resolve(callerPath, path);
}
if (!this.importCache[path]) {
let defineCall = arguments.length > 1 ? arguments[1] : require(path);
if (typeof defineCall === 'object') {
// ES6 module compatibility
defineCall = defineCall.default;
}
this.importCache[path] = defineCall(this, DataTypes);
}
return this.importCache[path];
}
モデルを読み込む部分がパス文字列を引数として渡す形になっているようです。
ビルド前の__dirname
とビルド後の__dirname
が変わってしまうのでエラーが起きている感じですね。
解決策
色々調べたのですが、webpack側でどうにかする方法はおそらく無いようです。
というわけで強引ですが、copy-webpack-plugin
を使って、modelフォルダをbuildフォルダにコピーすることにします。
var CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
webpack: (config, options, webpack) => {
config.entry.main = './server/index.js'
config.plugins = [
new CopyWebpackPlugin([{from: './server/models/', to:'./server/models/'}], {ignore: ['index.js']})
]
return config
}
}
テンプレートで使われているのがbackpack.jsなので、webpackの場合は適宜読み替えてください。
fromとtoの文字列が同じですが、toはwebpack出力先のフォルダがルートになるためです。
実際は、fromが”ルートディレクトリ/server/models/”なのに対して、
toは”ルートディレクトリ/build/server/models/”となります。
おわりに
もっとエレガントな解決法があったら何卒ご教授くださいませ…