I deployed a Django+VueJS app that uses django webpack loader in order to render Vue apps in my Django templates. I used Nginx and Gunicorn to deploy the app to a DigitalOcean VPS, everything works without any problem but i have some doubts on how to edit my components in production, since i'm fairly new to Vue
Here is my vue.config:
const BundleTracker = require("webpack-bundle-tracker");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const pages = {
'main': {
entry: './src/main.js',
chunks: ['chunk-vendors']
},
}
module.exports = {
pages: pages,
runtimeCompiler: true,
filenameHashing: false,
productionSourceMap: false,
publicPath: process.env.NODE_ENV === 'production'
? 'static/vue'
: 'http://localhost:8080/',
outputDir: '../django_vue_mpa/static/vue/',
chainWebpack: config => {
config.optimization
.splitChunks({
cacheGroups: {
moment: {
test: /[\\/]node_modules[\\/]moment/,
name: "chunk-moment",
chunks: "all",
priority: 5
},
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "chunk-vendors",
chunks: "all",
priority: 1
},
},
});
Object.keys(pages).forEach(page => {
config.plugins.delete(`html-${page}`);
config.plugins.delete(`preload-${page}`);
config.plugins.delete(`prefetch-${page}`);
})
config
.plugin('BundleTracker')
.use(BundleTracker, [{filename: '../vue_frontend/webpack-stats.json'}]);
// Uncomment below to analyze bundle sizes
// config.plugin("BundleAnalyzerPlugin").use(BundleAnalyzerPlugin);
config.resolve.alias
.set('__STATIC__', 'static')
config.devServer
.public('http://localhost:8080')
.host('localhost')
.port(8080)
.hotOnly(true)
.watchOptions({poll: 1000})
.https(false)
.headers({"Access-Control-Allow-Origin": ["*"]})
}
};
So in order to deploy the Vue part i did npm run build and npm created a bunch of files in my static directory. Now, every time i edit a component, in order to see the changes on the web, i do npm run build every time, which takes some time. Is this how am i supposed to do it? Or is there a shorter way?
I don't know about django, But I know about vue..
is this how am I supposed to do it?
For me, I don't suggest it, you can use your django as a backend for your frontend
that should mean you would have 2 servers running. 1 for your django and 1 for your vue app. use XHR request to access your django App, remember to handle CORS. IMHO I don't want vue to be used as a component based framework.
is there a shorter way.
YES, and this is how you do it.
add to package.json
{
...,
scripts: {
...,
'watch' : 'vue-cli-service build --watch --inline-vue',
...,
}
}
while using the following settings in vue.config.js
module.exports = {
'publicPath': '/django/path/to/public/folder',
'outputDir': '../dist',
'filenameHashing': false,
runtimeCompiler: true,
'css': {
extract: true,
},
}
i forgot about how publicPath and outputDir works..
but you can check it out here https://cli.vuejs.org/config/#publicpath
regarding the code on the package.json file..
you can check it here
https://github.com/vuejs/vue-cli/issues/1120#issuecomment-380902334
The Yeoman generated Gruntfile.js dies during a grunt build with:
Running "rev:dist" (rev) task
dist/public/app/app.js >> b90d2f58.app.js
dist/public/app/vendor.js >> 2deb5480.vendor.js
Warning: Unable to read "dist/public/bower_components/uri.js" file (Error code: EISDIR). Used --force, continuing.
Clearly it is interpreting the uri.js component directory as a file! One simple fix is to rename the uri.js component to uri_js or something similar. But rather than do that, is there an easy switch to add to the utility that does the Hashing to know that 'uri.js' is not a file??? I already tried adding "filter: 'isFile'" to every place in the Gruntfile that has *.js as a pattern, to no avail.
Anyone who has already seen this, your help is appreciated. For now I am simply doing grunt build --force. Thanks
I finally discovered that one can exclude this bower_component from the rename process. The key is that order of the files in the rev piece is dependent on the order of selection. So I modified this section of my Gruntfile.js ... and all is well.
// Renames files for browser caching purposes
rev: {
dist: {
files: {
src: [
'<%= yeoman.dist %>/public/{,*/}*.js',
'<%= yeoman.dist %>/public/{,*/}*.css',
'<%= yeoman.dist %>/public/assets/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/public/assets/fonts/*',
'!<%= yeoman.dist %>/public/bower_components/uri.js'
]
}
}
The crucial addition was this last piece:
'!<%= yeoman.dist %>/public/bower_components/uri.js'
I hope this helps someone else with with this issue!
I want to copy all js into one folder which belongs to angular Like angular, angular-cookies, angular-resource and angular-route etc.
I was trying to add regex for cwd but it fails to copy.
Folder Structure:
app(route folder)
->angular
->angular-cookies
->angular-resource
->angular-route
copy: {
main: {
files: [
{expand: true, cwd: '<%= yeoman.app %>/angular*', src: ['*.js'], dest:'angular'},
]
}
}
Running Karma + Jasmine Tests with RequireJS -- Getting off the ground
Help! . . . _ _ _ . . . SOS!
Currently, I have an exercise project up for getting comfortable with KarmaJS -- and Unit Testing, at large. The broad issue is that I really have no transparent view of what Karma is doing behind the scenes, and I can't seem to find adequate documentation in relevant areas. Without further delay...
Here is my folder structure:
root
|-/lib
|-/[dependencies] (/angular, /angular-mocks, /bootstrap, /etc) # from bower
|-/src
|-/[unreferenced directories] (/js, /css, /views) # not referenced anywhere
|-app.js # sets up angular.module('app', ...)
|-globals.js # may be referenced in RequireJS main file; not used.
|-index.html # loads bootstrap.css and RequireJS main file
|-main.js # .config + require(['app', 'etc'])
|-routeMap.js # sets up a single route
|-test-file.js # *** simple define(function(){ return {...}; })
|-/test
|-/spec
|-test-test-file.js # *** require || define(['test-file'])
|-.bowerrc # { "directory": "lib" }
|-bower.json # standard format
|-karma.conf.js # *** HELP!
|-test-main.js # *** Save Our Souls!!!
karma.conf.js
// Karma configuration
// Generated on Wed Nov 19 2014 15:16:56 GMT-0700 (Mountain Standard Time)
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine', 'requirejs'],
// list of files / patterns to load in the browser
files: [
//'test/spec/test-test-file.js',
//'lib/**/*.js',
//'src/**/*.js',
//'test/spec/**/*.js',
'test-main.js',
{pattern: 'lib/**/*.js', included: false},
{pattern: 'src/**/*.js', included: false},
{pattern: 'test/spec/*.js', included: true}
],
// list of files to exclude
exclude: [
'lib/**/!(angular|angular-mocks|angular-resource|angular-route|require|text).js',
'lib/**/**/!(jquery|bootstrap).js',
'src/app.js'
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false
});
};
test-main.js
var allTestFiles = [];
var TEST_REGEXP = /(spec|test)\.js$/i;
var pathToModule = function(path) {
return path.replace(/^\/base\//, '').replace(/\.js$/, '');
};
Object.keys(window.__karma__.files).forEach(function(file) {
if (TEST_REGEXP.test(file)) {
// Normalize paths to RequireJS module names.
allTestFiles.push(pathToModule(file));
}
});
require.config({
// Karma serves files under /base, which is the basePath from your config file
baseUrl: '/base/src',
paths: {
angular: '../lib/angular/angular',
ngRoute: '../lib/angular-route/angular-route',
jquery: '../lib/jQuery/dist/jquery',
bootstrap: '../lib/bootstrap/dist/js/bootstrap',
models: 'models',
controllers: 'controllers',
globals: 'globals',
routeMap: 'routeMap'
},
shim: {
angular: {
exports: 'angular'
},
ngRoute: {
deps: ['angular']
},
jquery: {
exports: '$'
},
bootstrap: {
deps: ['jquery']
}
},
// dynamically load all test files
deps: allTestFiles,
// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
});
test-test-file.js
console.log('....................');
define(function(){
//console.log('testing test-file', testFile);
describe('Testing testing', function(){
it('should work', function(){
expect(true).toEqual(true);
});
});
});
test-file.js
define('testFile', [], function(){
return function init(sandbox){
var app, application = app = sandbox.app
, globals = sandbox.globals;
return {
some: 'module'
};
};
});
Questions & Descriptions
Key points I would love to hear answers for are
what does { pattern: '...', include: true|false } do?
best way to exclude all the extra stuff inside the bower directories.
what files do I need to include in the test-main.js file?
what files do I need to include in the karma.conf.js file?
what does test-main.js actually do; what's it for?
The times I receive errors & issues is as soon as I wrap my spec in a define(...) call -- event when I give the module an ID -- define('someId', function(){ ... }) -- do I need to return something out of this module, as it is a define call?
Other times, I receive the 'ol ERROR: 'There is no timestamp for /base/src/app.js!'. "Timestamp, of course! How silly of me..." -- what in the world does this mean?! Sometimes I get the infamous "Executed 0 of 0 ERROR" -- I could also use some clarity here, please. Really, I get plenty of ERROR: '...no timestamp...' errors -- and even 404s when it seems I should be pulling that library in with the karma.conf.js files config...???
It even seems that usually when I explicitly tell karma to excludesrc/app.js I still get 404s and errors.
tl;dr
Obviously, I'm a bit of a confused novice about Karma and *DD at large...
I can run test-test-file.js fine when my karma.conf.js files array looks like [ 'test-main.js', 'test/spec/test-test-file.js' ] -- but, still, if I wrap my test in a RequireJS define call I get the "Mismatching anonymous define()" error mentioned above.
It seems that when I add { pattern: '...', include: false } then karma just doesn't add any of my files for the given pattern whatsoever (???).
If someone can even simply direct me toward how to use RequireJS with Karma -- namely so that I can just wrap my tests in a define/require call and pull in the module I want to test... That would be greatly appreciated.
As its somewhat difficult to keep these types of questions short and still provide adequate information, I hope I didn't make it too long.
EDIT
After reading the answer from glepretre and some fiddling on my own, I reconfigured my project as follows:
Moved test-main.js to test/test-main.js,
renamed test-test-file.js to testFileSpec.js -- moved it from test/spec to test/,
karma.conf.js:
...
// list of files / patterns to load in the browser
files: [
{pattern: 'lib/**/*.js', included: false},
{pattern: 'src/**/*.js', included: false},
{pattern: 'test/**/*Spec.js', included: false},
'test/test-main.js'
],
....
test/test-main.js:
/* **************** HOW COME THE DEFAULT (Karma-generated) CONFIGURATION DOES ***NOT WORK???
var allTestFiles = [];
var TEST_REGEXP = /(spec|test)\.js$/i;
var pathToModule = function(path) {
return path.replace(/^\/base\//, '').replace(/\.js$/, '');
};
Object.keys(window.__karma__.files).forEach(function(file) {
if (TEST_REGEXP.test(file)) {
// Normalize paths to RequireJS module names.
allTestFiles.push(pathToModule(file));
}
});
*/
var tests = [];
for (var file in window.__karma__.files) {
if (/Spec\.js$/.test(file)) {
tests.push(file);
}
}
require.config({
// Karma serves files under /base, which is the basePath from your config file
baseUrl: '/base/src',
paths: {},
shim: {},
// dynamically load all test files
//deps: allTestFiles,
//
deps: tests,
// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
});
I am now running Unit Tests successfully! Special Thanks to glepretre & all other contributors.
Thanks for any insight at all :)
OK, I will try to address each question at a time:
Question 1
what does { pattern: '...', included: true|false } do?
Karma's default behavior is to:
find all files matching the pattern (mandatory property)
watch them for changes (watched option) in order to restart your unit tests to give you live result when you are editing your code (works if only you leave the default autoWatch default value to true).
serve them using its own webserver (served option)
include them in the browser using <script> (included option)
So, in the files array of the karma config you can use default behavior by adding only string patterns:
files: [
// this will match all your JS files
// in the src/ directory and subdirectories
'src/**/*.js'
]
Or use the full object syntax to customize each option:
files: [
{pattern: 'src/**/*.js', watched: true, served: true, included: false}
]
Using requireJS, you DO NOT want them to be included because it will be in conflict with requireJS behavior!
Included. Description: Should the files be included in the browser using <script> tag? Use false if you want to load them manually, eg. using Require.js.
from karma/config/files docs
NB: Pay attention to the order in which you add the files/patterns in the array. It matters! For more understanding, set logLevel: config.LOG_DEBUG in your karma config.
Question 2
what files do I need to include in the karma.conf.js file?
At least all required files for the proper functioning of your components for unit testing.
Basically, all files listed in your define([]) and require() blocks.
Question 3
best way to exclude all the extra stuff inside the bower directories.
What are you trying to do exactly?
Based on what I wrote before, you can see that you can add selectively the files you will need in your tests.
I use to add the pattern '/bower_components/**/*.js' and even '/bower_components/**/*.html' when my bower packages are using templates. I never noticed any significant performance issue if that's what you are worried about... Up to you to define the file patterns you will need.
Question 4 & 5
what does test-main.js actually do; what's it for?
what files do I need to include in the test-main.js file?
The purpose of the test-main.js file is to find and load your test files before starting Karma. It connects the dots between Karma and requireJS
You must choose a convention to name your test files and then define the TEST_REGEXP to match all of them.
The "official" angular style guide and best practices for app structure recommends using the suffix *_test.js.
EDIT: Your regexp is not working because it is defined to catch "spec.js" || "test.js" at the end or your spec file name is ending by "file.js" ;) Please see http://regex101.com/r/bE9tV9/1
One more thing
I hope I was clear enough. You can have a look at our starter app structure for our projects using Angular + Require: angular-requirejs-ready. It's already set up and tested with both Karma and Protractor.
I am using grunt to build my project and have the following src structure:
app/src/client/pages/user/users.js
app/src/client/pages/user/users.html
app/src/client/pages/project/projects.js
app/src/client/pages/user/projects.html
Now, I am trying to build my project to look like this:
app/dist/client/users.html
I use the contrib-htmlmin plugin and my grunt config looks like this:
htmlmin: {
options: {
removeComments: true,
collapseWhitespace: true
},
partials: {
files: [
{
expand: true,
cwd: "app/src/client/pages/*/",
dest: "app/dist/client/",
src: ["*.html"]
}
]
}
But this is not working at all, no files are being minified.
Any suggestions?
As best I can tell, Grunt does not expand patterns in cwd, so your option
cwd: "app/src/client/pages/*/",
never gets converted to an array of matching directories.
You can follow my logic for this conclusion by starting at this line in the source. grunt.file.expandMapping (source here) doesn't call grunt.file.expand on your cwd pattern.
That doesn't mean you can't do it yourself. I've used the following pattern to accomplish something similar with grunt-contrib-sass when I have sass files spread out over several directories:
htmlmin: {
options: {
removeComments: true,
collapseWhitespace: true
},
partials: {
files: grunt.file.expand(['app/src/client/pages/*/']).map(function(cwd) {
return {
expand: true,
cwd: cwd,
dest: "app/dist/client/",
src: ["*.html"]
};
}),
}