sequelize / express-example

A proposal for the usage of Sequelize within an Express.JS application.
MIT License
2.5k stars 773 forks source link

Support automatic model configuration with webpack #74

Closed Aditya94A closed 4 years ago

Aditya94A commented 6 years ago

I'm talking about the index.js file under models that reads it's directory and finds all the other models to incorporate into the current db instance.

I'm trying to get it to work with babel+webpack, but since after compilation the working directory (__dirname) no longer has those models, the index.js file is unable to find them.

So I've had to use the following less than ideal solution to manually insert my models:

import Sequelize from 'sequelize';

import { ENV } from '../../config';
import sequelizeConfig from '../sequelize_config.json';
import userModel from './user';

const config = sequelizeConfig[ENV];

const db = {};

const dbUrl = process.env[config.use_env_variable];

const { database, username, password } = config;

const sequelize = dbUrl
  ? new Sequelize(dbUrl)
  : new Sequelize(database, username, password, config);

db.User = sequelize.import('User', userModel);
sequelize.sync();

Object.keys(db).forEach((modelName) => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

export { db as Models, sequelize };

Obviously, I'd prefer not to have to do this manually for every model I add. Is there a way to make automatic model detection work with webpack? (Here's my webpack config)

zainzafar commented 6 years ago

I'm having the same issue. Were you able to figure this out?

Aditya94A commented 6 years ago

@zainzafar Sadly, no :(

I eventually gave up on using webpack/babel completely since node v8 is like 99% ES6 compliant already and so we no longer really need babel for the most part.

aguynamedben commented 6 years ago

Thanks for working on Sequelize. I like it a lot and mean to provide constructive feedback.

I'm having the same problem. This also applies to Umzug migrations. From what I've learned, some Node.js-centric dependencies expect to be able to crawl a directory and dynamically require() things at runtime (i.e. Umzug migrations/ directory, models/index.js in Sequelize) are a world of pain in a Webpack/Babel/Electron world.

For migrations, I just gave up and just built my own small migration framework that doesn't have dynamic require()'s and following your simple but annoying strategy of importing each migration.

Once I got past that, I hit the same exact thing with Sequelize models being dynamically imported. I'll probably just use the workaround for now so I can use models.

It would be nice if Sequelize and Umzug were a little less aggressive about assuming things about the environment they operate in. require(), import, import() all seem to be a mess between various JavaScript transpilers and environments. "Use pure Node.js 10.x" is a fine solution, but all my other code is using Webpack, so it's really fragments my codebase into 2 styles (some Webpack/Babel, some pure Node.js, can't import between).

I know "it's Webpack's fault", but there's still not a great solution. With Umzug, I almost got customResolver working with babel/ES6, until I realized that webpack-dev-server screws with module, making this method not work in a webpack-dev-server environment (module.constructor is undefined in webpack-dev-server environment, and I couldn't figure out a workaround to convert my transpiled code into an object).

mexx commented 5 years ago

I've got Webpack to include the models into the bundle, here my index.js:

import Sequelize from 'sequelize'
const env = process.env.NODE_ENV || 'development';
const config = require(`${__dirname}/../config/config.js`)[env];
const db = {};

let sequelize;
if (config.use_env_variable) {
  sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
  sequelize = new Sequelize(config.database, config.username, config.password, config);
}

const context = require.context('.', true, /^\.\/(?!index\.js).*\.js$/, 'sync')
context.keys().map(context).forEach(module => {
  const sequelizeModel = module(sequelize, Sequelize);
  db[sequelizeModel.name] = sequelizeModel;
})

Object.keys(db).forEach(modelName => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

export default db;
incompletude commented 5 years ago

I've got Webpack to include the models into the bundle, here my index.js:

import Sequelize from 'sequelize'
const env = process.env.NODE_ENV || 'development';
const config = require(`${__dirname}/../config/config.js`)[env];
const db = {};

let sequelize;
if (config.use_env_variable) {
  sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
  sequelize = new Sequelize(config.database, config.username, config.password, config);
}

const context = require.context('.', true, /^\.\/(?!index\.js).*\.js$/, 'sync')
context.keys().map(context).forEach(module => {
  const sequelizeModel = module(sequelize, Sequelize);
  db[sequelizeModel.name] = sequelizeModel;
})

Object.keys(db).forEach(modelName => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

export default db;

This does not work for me. At const model = module(sequelize, Sequelize) I get an error stating module is not a function.

astiag commented 4 years ago

@incompletude you can do like this:

context.keys().map(context).forEach(({ default: module }) => {...

papb commented 4 years ago

Hello everyone! Sorry to take long to address this issue.

It would be nice if Sequelize and Umzug were a little less aggressive about assuming things about the environment they operate in.

I agree.

I have replaced the previous example in this repository with a new, modern example that no longer uses sequelize.import nor reads the filesystem to detect modules. Things should just work now.

Let me know if anyone has further questions, thank you!!

AwolDes commented 3 years ago

@papb I'm still running into trouble with associations on lambda using webpack & sequelize. I've submitted an issue here with a PoC repo: https://github.com/sequelize/sequelize/issues/12874

Unsure if it's the way my models are created/associated, or something a bit more sinister. I've tried the various different methods so far and no luck.

papb commented 3 years ago

Hi @AwolDes, I've just replied you in that issue :grinning:

@ everyone else: please also look at https://github.com/sequelize/sequelize/issues/13169 about using Sequelize with Webpack.